DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Coco
Coco

Posted on

Text carousel and image carousel using CSS?

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 diagram, maybe you will say, isn’t this a very simple translation 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);
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 {
  // the number of items
  --s: 6;
  // container's height
  --h: 36;
  // per animation duration
  --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));
  }
}
Enter fullscreen mode Exit fullscreen mode

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 we 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>
Enter fullscreen mode Exit fullscreen mode
: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);
  }
}
Enter fullscreen mode Exit fullscreen mode

A very simple animation:

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;
  --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));
  }
}
Enter fullscreen mode Exit fullscreen mode

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

Someone who has actually developed a 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>
    <!-- Fill the first set of data -->
    <li>Lorem ipsum 1111111</li>
  </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

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>
    <!--Fill the first set of data-->
    <li>Lorem ipsum 1111111</li>
  </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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

Image 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

Finally

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

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.

Top comments (4)

Collapse
tlstechtrekker profile image
Tami Schultz • Edited on

Thank you SO much - been looking for an easy way to implement without a lot of overhead from libraries and such! BTW, I just joined Dev.to - you're my first post to read!

Collapse
chokcoco profile image
Coco Author

Haha, Thany you. BTW, I think you are lucky to have found the treasure in the first post.

Collapse
craftyminer1971 profile image
CraftyMiner1971

I love it that you don't use any JS in any of your files, on CodePen too!

Collapse
chokcoco profile image
Coco Author

Haha, Thank you. After all, I am a CSS magician, how can I use JAVASCRIPT?

πŸ€” Did you know?

Β 
✍️ Writing your own article is easy (we even support markdown)