Text carousel and image carousel? CSS is a cinch

chokcoco發表於2022-11-23

Today, I will share an animation technique that can be used in real business.

Skillfully use frame-by-frame animation and tweened animation to achieve an infinite loop carousel effect , like this:

Seeing the above schematic diagram, some students can't help but ask, isn't this a very simple displacement animation?

Let's make a simple analysis. On the surface, it seems that there are only elements transform: translate() in displacement, but note that there are two difficulties here:

  1. This is an infinite carousel effect, our animation needs to support infinite carousel switching of any number of elements
  2. Because it is a carousel, when it runs to the last one, it needs to animate to the first element

At this point, you can pause and think for a moment. If there are 20 elements and you need to perform a similar infinite carousel broadcast, using CSS to achieve, how would you do it?

Frame-by-frame animation controls overall switching

First, I need to use the frame-by-frame animation effect, also known as the step easing function , using the steps in animation-timing-function , the syntax is as follows:

 {
    /* Keyword values */
    animation-timing-function: step-start;
    animation-timing-function: step-end;
    /* Function values */
    animation-timing-function: steps(6, start)
    animation-timing-function: steps(4, end);
}

If you are not particularly familiar with the syntax of steps , I strongly recommend that you read my article first - CSS animation in simple terms, it plays a crucial role in understanding this article.

Ok, the example at the beginning of the article, suppose we have this HTML structure:

 <div class="g-container">
  <ul>
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
  </ul>
</div>

First, we implement a simple layout like this:

Here, to achieve a carousel effect, and it is an arbitrary number, we can use animation-timing-function: steps() :

 :root {
  // 輪播的個數
  --s: 6;
  // 單個 li 容器的高度
  --h: 36;
  // 單次動畫的時長
  --speed: 1.5s;
}
.g-container {
  width: 300px;
  height: calc(var(--h) * 1px);
}
ul {
  display: flex;
  flex-direction: column;
  animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;
}
ul li {
  width: 100%;
}
@keyframes move {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, calc(var(--s) * var(--h) * -1px));
  }
}

Don't panic when you see a few CSS variables above, it's actually quite understandable:

  1. calc(var(--speed) * var(--s)) : The duration of a single animation * the number of rotations, that is, the total animation duration
  2. steps(var(--s)) is the frame number of the frame-by-frame animation, here is steps(6) , well understood
  3. calc(var(--s) * var(--h) * -1px)) The height of a single li container * the number of carousels, which is actually the overall height of the ul, which is used to set the end value of the frame-by-frame animation

The above effect is actually as follows:

If you add overflow: hidden to the container, this is the effect:

In this way, we get the overall structure, at least, the whole effect is circular.

But since it's just frame-by-frame animation, only the transition can be seen, but there is no transition animation effect between each frame. So, next, we have to introduce motion tweens.

Use tween animation to switch between two sets of data

We need to use tween animation to achieve dynamic switching effects.

This step is actually very simple. What we need to do is to move a set of data from state A to state B using transform .

If you take one out for demonstration, the rough code is as follows:

 <div class="g-container">
  <ul style="--s: 6">
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
  </ul>
</div>
 :root {
  --h: 36;
  --speed: 1.5s;
}
ul li {
  height: 36px;
  animation: liMove calc(var(--speed)) infinite;
}
@keyframes liMove {
  0% {
    transform: translate(0, 0);
  }
  80%,
  100%  {
    transform: translate(0, -36px);
  }
}

A very simple animation:

bgg1

Based on the above effects, if we combine the frame-by-frame animation mentioned at the beginning with the tween animation here, the overall movement of ul is stacked with the single movement of li:

 :root {
  // 輪播的個數
  --s: 6;
  // 單個 li 容器的高度
  --h: 36;
  // 單次動畫的時長
  --speed: 1.5s;
}
.g-container {
  width: 300px;
  height: calc(var(--h) * 1px);
}
ul {
  display: flex;
  flex-direction: column;
  animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;
}
ul li {
  width: 100%;
  animation: liMove calc(var(--speed)) infinite;
}
@keyframes move {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, calc(var(--s) * var(--h) * -1px));
  }
}
@keyframes liMove {
  0% {
    transform: translate(0, 0);
  }
  80%,
  100%  {
    transform: translate(0, calc(var(--h) * -1px));
  }
}

You can get this effect:

Wow, the magical chemical reaction happened! Based on the combination of frame-by-frame animation and tween animation , we have almost achieved a carousel effect.

Of course, there is a slight flaw. You can see that the last set of data is transformed from the sixth set of data to a set of empty data:

Fill the first set of data in the header at the end

Students who have actually developed carousel must know that here, it is actually very easy to handle. We only need to fill in the first data of a group of headers at the end:

Modify our HTML:

 <div class="g-container">
  <ul>
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
    <!--末尾補一個首條資料-->
    <li>Lorem ipsum 1111111</li>
  </ul>
</div>

So, let's look at the effect again:

Beautiful! If you still have doubts, we add overflow: hidden to the container, the actual effect is as follows, through the additional last set of data, our entire animation is just perfectly connected, a perfect carousel effect:

For the complete code, you can click here: CodePen Demo -- Vertical Infinity Loop

Horizontal infinite carousel

Of course, the vertical rotation is realized, and the horizontal effect is the same.

In addition, we can fill in the CSS variable value in the style in the HTML structure, and pass in the actual number of li, so as to adapt to different animations according to the number of li:

 <div class="g-container">
  <ul style="--s: 6">
    <li>Lorem ipsum 1111111</li>
    <li>Lorem ipsum 2222222</li>
    <li>Lorem ipsum 3333333</li>
    <li>Lorem ipsum 4444444</li>
    <li>Lorem ipsum 5555555</li>
    <li>Lorem ipsum 6666666</li>
    <!--末尾補一個首尾資料-->
    <li>Lorem ipsum 1111111</li>
  </ul>
</div>

The CSS code of the whole animation is basically the same. We only need to change the transform value of the two animations, from vertical displacement to horizontal displacement:

 :root {
  --w: 300;
  --speed: 1.5s;
}
.g-container {
  width: calc(--w * 1px);
  overflow: hidden;
}
ul {
  display: flex;
  flex-wrap: nowrap;
   animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;
}
ul li {
  flex-shrink: 0;
  width: 100%;
  height: 100%;
  animation: liMove calc(var(--speed)) infinite;
}
@keyframes move {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(calc(var(--s) * var(--w) * -1px), 0);
  }
}
@keyframes liMove {
  0% {
    transform: translate(0, 0);
  }
  80%,
  100%  {
    transform: translate(calc(var(--w) * -1px), 0);
  }
}

In this way, we can easily convert it into a horizontal effect:

For the complete code, you can click here: CodePen Demo -- Horizontal Infinity Loop

Carousel? not a problem

OK, the above is just the text version of the carousel, what if it is a picture?

No problem, the method is the same. Based on the above code, we can easily modify it to get the carousel effect of the image version.

The code is the same, so it will not be listed, just look at the effect:

For the complete code, you can click here: CodePen Demo -- Horizontal Image Infinity Loop

Once you've mastered this technique, you can apply it to a lot of carousel effects that only require a simplified version.

To briefly summarize, very interesting techniques:

  1. Use frame-by-frame animation to achieve an overall carousel loop effect
  2. Use tween animation to achieve specific animation effects from state A to state B *
  3. Frame-by-frame animation with tween animation to form the effect of the overall carousel
  4. By adding a set of header data to the end of the HTML structure, the connection of the overall animation is realized
  5. Through the style tag of the HTML element, using CSS variables, fill in the actual number of DOM participating in the cycle, you can realize the connection between JavaScript and CSS

at last

OK, this is the end of this article, I hope this article will help you :)

If you want to get the most interesting CSS information, don't miss my official account -- iCSS front-end anecdotes ?

More wonderful CSS technical articles are summarized in my Github -- iCSS , which will be updated continuously. Welcome to click star to subscribe to the collection.

If you have any questions or suggestions, you can communicate more. Original articles are limited in writing and knowledge. If there are any inaccuracies in the article, please let me know.

相關文章