Making an infinite CSS carousel

After searching and struggling for many hours, I still couldn’t find a good guide on how to make an infinite CSS carousel. There’s not reason this can’t be done using html and css, and yet almost every guide is using javascript, or css that doesn’t act…

After searching and struggling for many hours, I still couldn’t find a good guide on how to make an infinite CSS carousel. There’s not reason this can’t be done using html and css, and yet almost every guide is using javascript, or css that doesn’t actually work when you try it.

It’s so simple and yet a working example is just not available, so I’m sharing what we’ve done at Rhosys to make our brand carousel.

And of course you want to see the finished product first:
rhosys-brand-carousel



Diving into the code

Here’s out simple display:

<section class="user-cloud">
  <div class="brands-container">
    <div class="brands-carousel">
      <picture>
        <source srcset="assets/images/s-customer-cloud1.png"
            media="(max-width: 766px)" />
        <img src="assets/images/customer-cloud1.png" />
      </picture>
      <picture>
        <source srcset="assets/images/s-customer-cloud2.png"
            media="(max-width: 766px)" />
        <img src="assets/images/customer-cloud2.png" />
      </picture>
      <picture>
        <source srcset="assets/images/s-customer-cloud3.png"
            media="(max-width: 766px)" />
        <img src="assets/images/customer-cloud3.png" />
      </picture>
      <picture>
        <source srcset="assets/images/s-customer-cloud4.png"
            media="(max-width: 766px)" />
        <img src="assets/images/s-customer-cloud4.png" />
      </picture>
    </div>
  </div>
</section>

We have four images on mobile and only three on desktop. To make this responsive we are using the picture tag with source and img set. Img selectors didn’t work, so we use picture. No idea why, but rather than fighting with that it’s easier to do this. No messy x2 multiples or figuring out what the size of the elements should be on the screen.

Then we’ll add some nice padding and setup to our container.
*IMPORTANT: the max-width here should always been the same width as all your pictures, so that 100% means the full picture width:

.brands-container {
  max-width: 1050px;
  margin: auto;
  padding:0 1em;
  overflow: hidden;
}

.brands-carousel {
  position: relative;
  padding-left: 0;
  margin: 0;
  height: 200px;
  overflow: hidden;
}

.brands-carousel > div {
  width: 100%;
}

That’s the setup, which is relatively simple, and here’s the important setup:

# Each picture in the carousel is 100% of the parent.
.brands-carousel > picture {
  width: 100%;
  position: absolute;
  top: 0;
  display: flex;
  justify-content: center;
  animation: carousel 20s linear infinite;

  # It also starts off the screen until it is time.
  transform: translateX(100%);
}

I’m going to skip talking about the first-picture keyframe, but every picture get’s the same setup, it takes N seconds to move onto the screen and stay there until the next picture moves. Calculated on desktop there are three pictures, so each one gets 1/3 of the times on stage.

.brands-carousel > picture:nth-child(1) {
  animation-name: first-picture, carousel;
  animation-duration: 20s;
  animation-iteration-count: 1, infinite;
  animation-delay: 0s, 20s;
  transform: translateX(0%);
}
.brands-carousel > picture:nth-child(2) {
  animation-delay: Calc(20s * .33);
}
.brands-carousel > picture:nth-child(3) {
  animation-delay: Calc(20s * .66);
}
# The keyframes
@keyframes first-picture {
  0% { transform: translateX(0%); }
  7.5%, 33% { transform: translateX(0); }
  40.5%, 100% { transform: translateX(-100%); }
}

@keyframes carousel {
  0% { transform: translateX(100%); }
  7.5%, 33% { transform: translateX(0); }
  40.5%, 100% { transform: translateX(-100%); }
}

So the main keyframe is carousel. Since each image is on stage for 1/3 of the time, It will slide in taking 7.5% of the 20s time to do that, and stay there until the end of it’s 33%, and which time it transfers out. Since each image takes 7.5% to enter, it also has to take 7.5% to leave.
33% + 7.5% = 40.5.

And this almost totally works, except for one thing, until the 33% of 20s no image is fully displayed. The fix for this is a hack which shows the first image two times. We’ll show it on the screen to start until it leaves and at the same time we’ll show it off the screen to the right until it starts. We’ll then delay the second animation one full round. Because of this, we need the first-picture keyframe, and this works great.

# The keyframes for mobile
@keyframes first-picture-responsive {
  0% { transform: translateX(0%); }
  5.5%, 25% { transform: translateX(0); }
  30.5%, 100% { transform: translateX(-100%); }
}

@keyframes carousel-responsive {
  0% { transform: translateX(100%); }
  5.5%, 25% { transform: translateX(0); }
  30.5%, 100% { transform: translateX(-100%); }
}

Don’t show the forth picture on desktop

.brands-carousel > picture:last-child {
  display: none;
}

On mobile we’ll make some small adjustments, instead of 20s for 3, well have 27s for 4 images, each image gets 1/4 of the time on stage.

@media screen and (max-width: 766px) {
  .brands-carousel > picture {
    animation: carousel-responsive 27s linear infinite;
  }

  .brands-carousel > picture:nth-child(1) {
    animation-name: first-picture-responsive, carousel-responsive;
    animation-duration: 27s;
    animation-iteration-count: 1, infinite;
    animation-delay: 0s, 27s;
  }

  .brands-carousel > picture:nth-child(2) {
    animation-delay: Calc(27s * .25);
  }
  .brands-carousel > picture:nth-child(3) {
    animation-delay: Calc(27s * .50);
  }
  .brands-carousel > picture:nth-child(4) {
    animation-delay: Calc(27s * .75);
    display: block;
  }
}



Finishing up

If you want to change the time of the full animate loop replace the 20s with your new full time. To change how long a transition is on the screen reduce the 7.5% to a smaller value (and reduce the 40.5% by the same amount). To make any other change (i.e. increasing the length of time the image is static, you’ll need to compute that based on 33% of the total time and then recalculate the transition percentage.

Right now the static image is 7.5% to 33% that’s 25.5% of 20s (5.1s) on the screen. If you want that to be 6s on the screen without reducing the transition time (7.5% * 20s = 1.5s). Calculate the total new time 6 / .255 = 23.5s for the full animation and then new transition percentages are 1.5s / 23.5s = 6.4% so the new keyframes would be

# Updating all the 20s => 23.5s
@keyframes carousel {
  0% { transform: translateX(100%); }
  6.4%, 33% { transform: translateX(0); }
  39.4%, 100% { transform: translateX(-100%); }
}

And that’s it.

Here’s a link to the code


Print Share Comment Cite Upload Translate
APA
Warren Parad | Sciencx (2024-03-28T23:36:15+00:00) » Making an infinite CSS carousel. Retrieved from https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/.
MLA
" » Making an infinite CSS carousel." Warren Parad | Sciencx - Sunday April 11, 2021, https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/
HARVARD
Warren Parad | Sciencx Sunday April 11, 2021 » Making an infinite CSS carousel., viewed 2024-03-28T23:36:15+00:00,<https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/>
VANCOUVER
Warren Parad | Sciencx - » Making an infinite CSS carousel. [Internet]. [Accessed 2024-03-28T23:36:15+00:00]. Available from: https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/
CHICAGO
" » Making an infinite CSS carousel." Warren Parad | Sciencx - Accessed 2024-03-28T23:36:15+00:00. https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/
IEEE
" » Making an infinite CSS carousel." Warren Parad | Sciencx [Online]. Available: https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/. [Accessed: 2024-03-28T23:36:15+00:00]
rf:citation
» Making an infinite CSS carousel | Warren Parad | Sciencx | https://www.scien.cx/2021/04/11/making-an-infinite-css-carousel/ | 2024-03-28T23:36:15+00:00
https://github.com/addpipe/simple-recorderjs-demo