Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

Infinte Scrolling Carousel using CSS

1.60/5 (3 votes)
23 Oct 2018CPOL3 min read 8.7K   139  
Carousel using only CSS3 (without JavaScript and JS frameworks)

Introduction

We have a lot of readymade solutions for carousels from many UI/UX frameworks like Bootstrap, Glide, Flickity, etc. What if we want to build a carousel using HTML5 and CSS3 without depending on any 3rd party libraries. This article is about building a simple carousel without any JS code.

Background

In this article, we would take 4 DIVs of different colors and create an infinite scrolling carousel.

Step 1: Create DIVs and Style Them

First, we'll create 4 divs and keep them inside a parent container.

HTML
<div class="gallery">
  <div class="red"></div>
  <div class="blue"></div>
  <div class="yellow"></div>
  <div class="green"></div>
</div>

The CSS classes would be like this:

CSS
.gallery {
position: relative;
width:100%; /* takes the parent div's width*/

}

.gallery >div{
position: absolute;
top:0;
height: 200px; /* can be anything */
width: 100%;
}

Note: The parent div's position is relative and all the child divs are absolute. All the divs would be placed one behind the other inside the parent div 'gallery'.

Step 2: Create Controls to Slide Through the Carousel

This is where it gets interesting, we need some buttons/control to navigate through our carousel. But if we have an HTML button, that would require an onclick event listener which in turn should be handled by the JavaScript.

Let's do it the CSS way. Instead of buttons, we'll use radio buttons and the radio button.

Create 1 radio button for each div. The idea here is, if radio button 1 is clicked, the div 1 is shown and so on.

HTML
<div class="carousel-container">
 <input type="radio" name='control' id="slide1" class="carousel-control-radio">
 <input type="radio" name='control' id="slide2" class="carousel-control-radio">
 <input type="radio" name='control' id="slide3" class="carousel-control-radio">
 <input type="radio" name='control' id="slide4" class="carousel-control-radio">

 <div class="gallery">
  <div class="red"></div>
  <div class="blue"></div>
  <div class="yellow"></div>
  <div class="green"></div>
 </div>
</div>

In HTML5, we have an attribute in <label> tag 'for' which is useful to map the input element with its label. The other interesting property of this attribute is: The corresponding radio button gets checked when we click on the label assigned to it. We are going to use this feature to leverage our controls.

Note: I have enclosed the entire HTML block into a div with class carousel-container with position relative and any arbitrary width.

Let's implement the control. The logic is setting the opacity of all the divs to 0 and make the opacity of selected div as 1.

HTML
.gallery >div{ 
position: absolute;
top:0; 
height: 200px; /* can be anything */ 
width: 100%; 
opacity:0 /* all divs are hidden */

}

We'll overwrite the opacity of the selected radio button's div. How do we do that??

The general sibling combinator (~): It is used to select all the siblings after the selector.

HTML
#slide1:checked ~ .gallery > div:nth-child(1),
#slide2:checked ~ .gallery > div:nth-child(2),
#slide3:checked ~ .gallery > div:nth-child(3),
#slide4:checked ~ .gallery > div:nth-child(4)
{
  opacity: 1;
}

#slide1:checked ~ .gallery > div:nth-child(1) denotes when #slide1 is checked, select from the siblings that follows it -> .gallery div and the first child of it. We set the opacity to 1.

Now our output should look like this:

Image 1

The radio buttons will be hidden and only the labels of the radio button will act as our controls.

Step 3: Create Labels for Each Radio Button

HTML
<div class="slider-controls">
  <label for="slide1"></label>
  <label for="slide2"></label>
  <label for="slide3"></label>
  <label for="slide4"></label>
</div>

Now we need to keep the slider-controls to center of our carousel-container.

CSS
.slider-controls{
 position: absolute;
 width: 100%;
 top:100px;
}

Note: There is no text inside label. Exaclty! we are going to use CSS pseudo element to dynamically change the content of the text as '<' or '>' which will denote the direction of previous or next div.

As per our design, we would show the div when its corresponding radio button is selected.

Say radiobutton slide2 is checked: then '<' should be a control when clicked should go to slide 1 and '>' should be a control when clicked should go to slide 3.

So:

CSS
#slide2:checked ~ .slider-controls > label:nth-child(3)::after{
 content: '>';
 float:right; /*push the control on the right side*/
}
CSS
#slide2:checked ~ .slider-controls > label:nth-child(1)::after{
 content: '<';
 float:left; /*push the control on the left side*/
}

We don't need to show any other controls. We just need to show these two. SImilarly, for 3 and 4:

CSS
#slide3:checked ~ .slider-controls > label:nth-child(4)::after{
 content: '>';
 float:right; /*push the control on the right side*/
}
CSS
#slide3:checked ~ .slider-controls > label:nth-child(2)::after{
 content: '<';
 float:left; /*push the control on the left side*/
}
CSS
#slide4:checked ~ .slider-controls > label:nth-child(1)::after{
 content: '>';
 float:right; /*push the control on the right side*/
}
CSS
#slide4:checked ~ .slider-controls > label:nth-child(3)::after{
 content: '<';
 float:left; /*push the control on the left side*/
}

Note: Slide 4's next will be slide 1.

Now the first slide is a bit tricky.

This will have '>' pointing to slide 2 which is direct. and '<' should be the last slide. We will use the nth-last-child(1) pseudo element to select the last div.

CSS
#slide1:checked ~ .slider-controls > label:nth-child(2)::after{
 content: '>'
 float:right; /*push the control on the right side*/
}
CSS
#slide1:checked ~ .slider-controls > label:nth-last-child(1)::after{
 content: '<'
 float:left; /*push the control on the left side*/
}

This concludes our solution.

Image 2

Improvements

  • We can also add CSS transitions to smoothen our opacity transitions.
    CSS
    .gallery >div{
    position: absolute; top:0;
    height: 200px; /* can be anything */
    width: 100%;
    opacity:0 /* all divs are hidden */
    transtion: opacity 800ms ease-in-out;
    }
  • The radio buttons in the top can be hidden with display:none and the solution will still work.
  • The content of pseudo selector can be designed using border over the pseudo element instead of '>' or '<'
  • The divs background can be set as an image which created a beautiful gallery of images.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)