Custom carousel with images JS

ChrisChris
4 min read

Table of contents

Hi!

This time I wanted to try creating my own image carousel.

For this I will use opacity and JavaScript for adding and removing classes.

HTML

As for HTML I will create container that will hold three slides and buttons to navigate. Buttons will be styled to look like navigation dots on the bottom of the image.

<div class="home-container">
    <div class="slide " id="slide1">
      <img src="./img/dach-1.jpg" alt="roof">
      <div class="img-dimmer"></div>
      <div class="text-overlay">
        <div class="title">LOREM IPSUM DOLOR(slide1)</div>
        <div class="sub-title">SIT AMET CONSECTETUR ADIPISCING</div>
      </div>
    </div>

    <div class="slide" id="slide2">
      <img src="./img/dach-4.jpg" alt="roof">
      <div class="img-dimmer"></div>
      <div class="text-overlay">
        <div class="title">LOREM IPSUM DOLOR(slide2)</div>
        <div class="sub-title">SIT AMET CONSECTETUR ADIPISCING</div>
      </div>
    </div>

    <div class="slide" id="slide3">
      <img src="./img/dach-1.jpg" alt="roof">
      <div class="img-dimmer"></div>
      <div class="text-overlay">
        <div class="title">LOREM IPSUM DOLOR(slide3)</div>
        <div class="sub-title">SIT AMET CONSECTETUR ADIPISCING</div>
      </div>
    </div>

    <div class="nav-buttons">
      <button class="carousel-btn active-slide" id="carousel_btn_1">&nbsp;</button>
      <button class="carousel-btn" id="carousel_btn_2">&nbsp;</button>
      <button class="carousel-btn" id="carousel_btn_3">&nbsp;</button>
    </div>
  </div>

SCSS

First I will start styling the containers. My home container will have position relative, and all slide elements inside will have position absolute with same start point so they overlaps.

Then class sliding will be used to create animation effect to show our slides with transition of 1s.

Next I will hide 2 next slides so they are not visible on start.

.home-container{
  position: relative;
  width: 100%;
  height: 60vh;
  display: flex;
}
.slide{
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;    
  transition: opacity 1s;
}
.sliding{
  opacity: 1;  
}
#slide2, #slide3{ 
  opacity: 0;
}

Now we need to style our photos.

.home-container img{
  width: 100%;  
  height: 100%;
  object-fit: cover;
}
.img-dimmer{
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #000;
  opacity: 0.5;
}

And also our text inside.

.text-overlay{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 80%;
  transform: translate(-50%, -50%);
  color: $text-color-1;
}
.text-overlay .title{
  font-size: 3.5rem;
  font-weight: 700;
  letter-spacing: 0.5rem;
}
.text-overlay .sub-title{
  font-size: 2rem;
  font-weight: 400;
}

And finally we style our buttons for navigation.

.nav-buttons{
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
}
.nav-buttons .carousel-btn{
  width: 18px;
  height: 18px;
  border-radius: 25px;
  border: none;
  margin: 0 5px;
  opacity: 0.5;
  cursor: pointer;
}
.nav-buttons .active-slide{
  opacity: 1 ;
}

As for this state our carousel should look like this. I also used Raleway font for text.

sliders.PNG

JavaScript

For my variables I will need conatiner of buttons , all navigation buttons, all slides and variable of last clicked slide.

const nav_buttons_cont = document.querySelector('.nav-buttons')
const nav_buttons = document.querySelectorAll('.carousel-btn')
const slides = document.querySelectorAll('.slide')
var last_clicked = 'slide1'

First I will add event listener to my navigation buttons container.

nav_buttons_cont.addEventListener('click', (e)=>{})

Next inside our listener I want to disable buttons after user already clicked one for one second. This is how long our animation will last. With this I want to prevent to much clicks and make the sliding more error proof.

This place is also good to remove active slide indication classes from all buttons. Later we will add it depending on what button user clicked.

And the same for our sliding class, here I can remove this class from all slides, to later add it to this one that user clicked on.

nav_buttons_cont.addEventListener('click', (e)=>{

  nav_buttons.forEach(button =>{
    button.disabled = true
    button.classList.remove('active-slide')

    setTimeout(()=>{
      button.disabled = false;
    }, 1000)
  })

slides.forEach(slide =>{
    slide.classList.remove('sliding')
  })
})

Okay so for switching slides I will use switch statement with three cases using id of clicked button.

Lets see one case statement before I show the whole code.

switch (e.target.id){
    case 'carousel_btn_2':

      document.getElementById('slide2').style.opacity = '1'
      document.getElementById('slide2').classList.add('sliding')
      document.getElementById('carousel_btn_2').classList.add('active-slide')

      setTimeout(() => {
        document.getElementById(last_clicked).style.opacity = '0'
        last_clicked = 'slide2'
      }, 1000);
      break

We pass to the case statement clicked Id of the button. In this example we simulate clicked second button.

So we can change opacity of second slide to 1. Add class sliding for our animation with transition.

Also for the button we add active button class.

Lastly we use setTimeout function to prevent white flickering while changing the slides. This will assure that our previous slide will not disappear until our new one will load.

Inside this function we can set opacity to 0 to hide our last_clicked slide. Also here we need to update our last_clicked variable with slide we currently are modifying.

For next case statements we use same logic, we only change according slides and buttons.

Below whole event listener responsible for carousel navigation.

nav_buttons_cont.addEventListener('click', (e)=>{

  nav_buttons.forEach(button =>{
    button.disabled = true
    button.classList.remove('active-slide')

    setTimeout(()=>{
      button.disabled = false;
    }, 1000)
  })

  slides.forEach(slide =>{
    slide.classList.remove('sliding')
  })

  switch (e.target.id){

    case 'carousel_btn_1':    

      document.getElementById('slide1').style.opacity = '1'
      document.getElementById('slide1').classList.add('sliding')
      document.getElementById('carousel_btn_1').classList.add('active-slide')  

      setTimeout(() => {
        document.getElementById(last_clicked).style.opacity = '0'
        last_clicked = 'slide1'
      }, 1000);    
      break

    case 'carousel_btn_2':

      document.getElementById('slide2').style.opacity = '1'
      document.getElementById('slide2').classList.add('sliding')
      document.getElementById('carousel_btn_2').classList.add('active-slide')

      setTimeout(() => {
        document.getElementById(last_clicked).style.opacity = '0'
        last_clicked = 'slide2'
      }, 1000);
      break

    case 'carousel_btn_3':        

      document.getElementById('slide3').style.opacity = '1'
      document.getElementById('slide3').classList.add('sliding') 
      document.getElementById('carousel_btn_3').classList.add('active-slide')

      setTimeout(() => {
        document.getElementById(last_clicked).style.opacity = '0'
        last_clicked = 'slide3'
      }, 1000);        
      break
  }
})

Now our carousel should work properly :)

sliders2.PNG

If you find any mistakes or you have ideas how to refactor my solutions to be simpler/ better please let me know :)

0
Subscribe to my newsletter

Read articles from Chris directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Chris
Chris