An infinite/circular carousel with css flex and little JS
Tags: webdev, carousel, css, flex
Published: 2020-08-03 15:43:27

Lately I have been playing a lot with css (and finally yes I get to do what I love) I was actually thinking of several applications of flex order property. Last usecase I found helps to solve a small accessibility issue in signup/NDA forms head [here to see what it was](https://dev.to/technikhil314/a-use-case-of-accessibility-solved-with-flex-46fh). 

This one tries to create a bare minimum infinite/circular carousel with as less as 70 lines of code all included HTML,CSS,JS

### What do I mean by circular/infinite carousel?
> Its a carousel that has n number of slides and it keeps scrolling to right side (for LTR languages) and (n+1)th chilid is again 1st child. 

### So lets start
- I will be using css flex, flex order, scroll-snap and little bit of plain JS to make our carousel autoscroll. 
- This is going to be a bare minimum carousel

#### Lets take a look at basic HTML and css for our carousel
```
<div class="carouselWrapper">                
    <div class="carouselContainer">
        <div class="carouselItem">
            <img height="100px" width="100%" src="//via.placeholder.com/1000x100/FFFF00/000000/?text=Carousel+Item+21"
                alt="" />
        </div>
        <div class="carouselItem">
            <img height="100px" width="100%" src="//via.placeholder.com/1000x100/FF0000/FFFFFF/?text=Carousel+Item+22"
                alt="" />
        </div>
        <div class="carouselItem">
            <img height="100px" width="100%" src="//via.placeholder.com/1000x100/00FF00/000000?text=Carousel+Item+23"
                alt="" />
        </div>  
    </div>
</div>
```
and here is the css
```
.carouselWrapper {
  position: relative;
}

.carouselContainer {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
}
.carouselContainer .carouselItem {
  flex-grow: 0;
  flex-shrink: 0;
  max-width: 100%;
}
```
Check the codepen
{% codepen https://codepen.io/nikhil-001mehta/pen/NWxEBVz %}

You can get rid of that horizontal scroll bar using following css and add scroll snap to it
```
.carouselContainer {
  display: flex;
  flex-wrap: nowrap;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overflow-x: auto;
  scrollbar-width: 0;
  scrollbar-color: transparent transparent;
}
.carouselContainer::-webkit-scrollbar {
  display: none;
}
.carouselContainer .carouselItem {
    flex-grow: 0;
    flex-shrink: 0;
    max-width: 100%;
    // we are telling browser to align each item centrally to 
    // screen as it scrolls into viewport
    scroll-snap-align: center;
}
```
We have added following property `scroll-snap-type: x mandatory;` to `carouselContainer` class
> here We are telling browser to apply scroll snap on 
  horizontal axis and make it manadatory to scroll one item 
  fully to snap behaviour to kick in. 
  [check more details here](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type)

We are also adding `scroll-snap-align: center;` property to `carouselItem` class
> we are telling browser to align each item centrally to 
screen as it scrolls into viewport

{% codepen https://codepen.io/nikhil-001mehta/pen/gOrYRgx %}

Now lets add little bit of javascript
```
let index = 0;
const speed = 5;
const numberOfSlides = 3;
const carouselContainer = document.querySelector(".carouselContainer");
const carouselItemWidth = carouselContainer.scrollWidth / numberOfSlides;
setInterval(() => {
  carouselContainer.scrollBy(carouselItemWidth, 0);
  timeoutId = setTimeout(() => {
    index = index % numberOfSlides;
    let childToMove = carouselContainer.querySelectorAll(`.carouselItem`)[
      index
    ];
    // The line below move the item to end of carousel by 
    // manipulating its flex order
    childToMove.style.order =
      childToMove.style.order && childToMove.style.order === 0
        ? 1
        : +childToMove.style.order + 1;
    index++;
    clearTimeout(timeoutId);
  }, 1000);
}, speed * 1000);
```
And woohoo our carousel is running 
{% codepen https://codepen.io/nikhil-001mehta/pen/ExKYXba %}

Let me know your thoughts on this.