skip to Main Content

I’m working on a photo slider made by HTML+CSS+JS. Currently it has navigation arrows, dots, and autoplay function. The animation changes its direction according to the interaction with the corresponding arrows/dots, and it resets the timer on each click. I’m trying to improve it step by step, and currently into adding a progress bar that’ll fill automatically based on sliderSpeed.

Could you please help?

var timeout;

function setDirection(d) {
  document.querySelector('.slider').style.setProperty('--direction', d);
}
setDirection(1);
var slider = document.getElementsByClassName("slider")[0];
var sliderDots = Array.prototype.slice.call(document.getElementsByClassName("dots")[0].children);
var sliderContents = Array.prototype.slice.call(document.getElementsByClassName("elements")[0].children);
var sliderArrowLeft = document.getElementsByClassName("arrow-left")[0];
var sliderArrowRight = document.getElementsByClassName("arrow-right")[0];
var sliderSpeed = 4000,
  currentSlide = 0,
  currentActive = 0,
  sliderTimer = 0;

function playSlide(slide, d) {
  if (!(d === undefined)) {
    direction = d;
    setDirection(d);

    // Force it forwards after it's done:
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      setDirection(1);
    }, 1000)
  }
  for (var k = 0; k < sliderDots.length; k++) {
    sliderContents[k].classList.remove("active");
    sliderContents[k].classList.remove("inactive");
    sliderDots[k].classList.remove("active");
  }
  if (slide < 0) {
    slide = currentSlide = sliderContents.length - 1;
  }
  if (slide > sliderContents.length - 1) {
    slide = currentSlide = 0;
  }
  if (currentActive != currentSlide) {
    sliderContents[currentActive].classList.add("inactive");
  }
  sliderContents[slide].classList.add("active");
  sliderDots[slide].classList.add("active");
  currentActive = currentSlide;
  clearTimeout(sliderTimer);
  sliderTimer = setTimeout(function() {
    playSlide(currentSlide += 1);
  }, sliderSpeed)
}
sliderArrowLeft.addEventListener("click", function() {
  playSlide(currentSlide -= 1, -1);
})
sliderArrowRight.addEventListener("click", function() {
  playSlide(currentSlide += 1, 1);
})
for (var l = 0; l < sliderDots.length; l++) {
  sliderDots[l].addEventListener("click", function() {
    let d = sliderDots.indexOf(this) - currentSlide
    playSlide(currentSlide = sliderDots.indexOf(this), Math.sign(d));
  })
}
playSlide(currentSlide);
.slider {
  overflow: hidden;
  position: relative;
}

.contents {
  width: 100%;
  height: 200px;
  position: relative;
  overflow: hidden;
}

.arrow-left,
.arrow-right {
  width: 50px;
  height: 50px;
  bottom: 0;
  cursor: pointer;
  display: block;
  text-align: center;
  line-height: 50px;
  background: rgb(200, 200, 200);
  position: absolute;
  z-index: 2;
}

.arrow-left {
  left: 0;
}

.arrow-right {
  right: 0;
}

.dots {
  height: 14px;
  bottom: 0;
  left: 50%;
  font-size: 0;
  text-align: right;
  position: absolute;
  z-index: 2;
  transform: translateX(-50%);
}

.dot {
  width: 12px;
  height: 12px;
  margin-left: 5px;
  margin-right: 5px;
  display: inline-block;
  cursor: pointer;
  border-style: solid;
  border-width: 1px;
  border-color: rgb(100, 100, 100);
}

.dot.active {
  background: rgb(200, 200, 200);
}

.elements {
  width: 100%;
  overflow: hidden;
  transform: translate(0px);
}

.image {
  width: 100%;
  height: 100px;
  top: 0;
  position: absolute;
  opacity: 0;
}

.image span {
  width: 100%;
  height: 100px;
  text-align: center;
  line-height: 100px;
  display: block;
  background: rgb(200, 200, 200);
}

.image.active {
  position: relative;
  z-index: 1;
  opacity: 1;
}

.image.inactive {
  z-index: -3;
  opacity: 1;
}

.image.active span {
  animation: show .5s ease-in-out forwards;
}

.image.inactive span {
  animation: hide .5s ease-in-out forwards;
}

@keyframes show {
  0% {
    transform: translateX(calc(var(--direction)*100%));
  }
  100% {
    transform: translateX(0);
  }
}

@keyframes hide {
  0% {
    opacity: 1;
    transform: translateX(0);
  }
  100% {
    opacity: 0;
    transform: translateX(calc(-1*var(--direction)*100%));
  }
}

.bar-holder {
  width: 100%;
  background: rgb(200, 200, 200);
}

.bar {
  width: 10%;
  height: 10px;
  background: rgb(255,0,0);
}
<div class="slider">
  <div class="contents">
    <div class="arrow-left">prev</div>
    <div class="arrow-right">next</div>
    <div class="dots">
      <li class="dot"></li>
      <li class="dot"></li>
      <li class="dot"></li>
    </div>
    <div class="elements">
      <div class="image"><span>image 1</span></div>
      <div class="image"><span>image 2</span></div>
      <div class="image"><span>image 3</span></div>
    </div>
  </div>
  <div class="bar-holder">
    <div class="bar"></div>
  </div>

</div>

2

Answers


  1. add this function

    function updateProgressBar() {
        // Calculate the percentage progress
        const progress = (currentSlide + 1) / sliderContents.length * 100;
        const progressBar = document.querySelector(".bar");
        progressBar.style.width = progress + "%";
      }
    

    and call it inside the playSlide function

    Login or Signup to reply.
  2. I edited your snipped such that it uses a CSS animation. The duration of the animation is set using javascript in the first line of your playSlide() function.
    This uses the efficiency of the browsers css rendering engine.
    I marked the lines that I changed with comments, e.g. //====Line added====

    var timeout;
    
    function setDirection(d) {
      document.querySelector('.slider').style.setProperty('--direction', d);
    }
    setDirection(1);
    var slider = document.getElementsByClassName("slider")[0];
    var sliderDots = Array.prototype.slice.call(document.getElementsByClassName("dots")[0].children);
    var sliderContents = Array.prototype.slice.call(document.getElementsByClassName("elements")[0].children);
    var sliderArrowLeft = document.getElementsByClassName("arrow-left")[0];
    var sliderArrowRight = document.getElementsByClassName("arrow-right")[0];
    var sliderSpeed = 4000,
      currentSlide = 0,
      currentActive = 0,
      sliderTimer = 0;
    
    function playSlide(slide, d) {
      //====Lines added====
     var progressIndicatorBar = document.querySelector('.bar'); 
     progressIndicatorBar.style.animationDuration = sliderSpeed + 'ms';
      progressIndicatorBar.classList.remove('bar');
      setTimeout(() => progressIndicatorBar.classList.add('bar'), 1);
      //====End of new lines====
      if (!(d === undefined)) {
        direction = d;
        setDirection(d);
    
        // Force it forwards after it's done:
        clearTimeout(timeout);
        timeout = setTimeout(function() {
          setDirection(1);
        }, 1000)
      }
      for (var k = 0; k < sliderDots.length; k++) {
        sliderContents[k].classList.remove("active");
        sliderContents[k].classList.remove("inactive");
        sliderDots[k].classList.remove("active");
      }
      if (slide < 0) {
        slide = currentSlide = sliderContents.length - 1;
      }
      if (slide > sliderContents.length - 1) {
        slide = currentSlide = 0;
      }
      if (currentActive != currentSlide) {
        sliderContents[currentActive].classList.add("inactive");
      }
      sliderContents[slide].classList.add("active");
      sliderDots[slide].classList.add("active");
      currentActive = currentSlide;
      clearTimeout(sliderTimer);
      sliderTimer = setTimeout(function() {
        playSlide(currentSlide += 1);
      }, sliderSpeed)
    }
    sliderArrowLeft.addEventListener("click", function() {
      playSlide(currentSlide -= 1, -1);
    })
    sliderArrowRight.addEventListener("click", function() {
      playSlide(currentSlide += 1, 1);
    })
    for (var l = 0; l < sliderDots.length; l++) {
      sliderDots[l].addEventListener("click", function() {
        let d = sliderDots.indexOf(this) - currentSlide
        playSlide(currentSlide = sliderDots.indexOf(this), Math.sign(d));
      })
    }
    playSlide(currentSlide);
    .slider {
      overflow: hidden;
      position: relative;
    }
    
    .contents {
      width: 100%;
      height: 200px;
      position: relative;
      overflow: hidden;
    }
    
    .arrow-left,
    .arrow-right {
      width: 50px;
      height: 50px;
      bottom: 0;
      cursor: pointer;
      display: block;
      text-align: center;
      line-height: 50px;
      background: rgb(200, 200, 200);
      position: absolute;
      z-index: 2;
    }
    
    .arrow-left {
      left: 0;
    }
    
    .arrow-right {
      right: 0;
    }
    
    .dots {
      height: 14px;
      bottom: 0;
      left: 50%;
      font-size: 0;
      text-align: right;
      position: absolute;
      z-index: 2;
      transform: translateX(-50%);
    }
    
    .dot {
      width: 12px;
      height: 12px;
      margin-left: 5px;
      margin-right: 5px;
      display: inline-block;
      cursor: pointer;
      border-style: solid;
      border-width: 1px;
      border-color: rgb(100, 100, 100);
    }
    
    .dot.active {
      background: rgb(200, 200, 200);
    }
    
    .elements {
      width: 100%;
      overflow: hidden;
      transform: translate(0px);
    }
    
    .image {
      width: 100%;
      height: 100px;
      top: 0;
      position: absolute;
      opacity: 0;
    }
    
    .image span {
      width: 100%;
      height: 100px;
      text-align: center;
      line-height: 100px;
      display: block;
      background: rgb(200, 200, 200);
    }
    
    .image.active {
      position: relative;
      z-index: 1;
      opacity: 1;
    }
    
    .image.inactive {
      z-index: -3;
      opacity: 1;
    }
    
    .image.active span {
      animation: show .5s ease-in-out forwards;
    }
    
    .image.inactive span {
      animation: hide .5s ease-in-out forwards;
    }
    
    @keyframes show {
      0% {
        transform: translateX(calc(var(--direction)*100%));
      }
      100% {
        transform: translateX(0);
      }
    }
    
    @keyframes hide {
      0% {
        opacity: 1;
        transform: translateX(0);
      }
      100% {
        opacity: 0;
        transform: translateX(calc(-1*var(--direction)*100%));
      }
    }
    
    .bar-holder {
      width: 100%;
      background: rgb(200, 200, 200);
    }
    
    .bar {
      width: 10%;
      height: 10px;
      background: rgb(255,0,0);
      /*====Line added====*/
      animation: progress-indicator infinite linear;
    }
    /*====Animation added====*/
    @keyframes progress-indicator {
      0% {
        width: 0%;
      }
      100% {
        width: 100%;
      }
    }
    <div class="slider">
      <div class="contents">
        <div class="arrow-left">prev</div>
        <div class="arrow-right">next</div>
        <div class="dots">
          <li class="dot"></li>
          <li class="dot"></li>
          <li class="dot"></li>
        </div>
        <div class="elements">
          <div class="image"><span>image 1</span></div>
          <div class="image"><span>image 2</span></div>
          <div class="image"><span>image 3</span></div>
        </div>
      </div>
      <div class="bar-holder">
        <div class="bar"></div>
      </div>
    
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search