I’m following this great solution to make a slider https://stackoverflow.com/a/70340585/18736427
It uses a good technique where once the slide reaches the last one, it will insert the first/last one into the previous/last place to make a loop effect.
However, this effect is instant…When you click next once it reaches the last slide, the first slide will always immediately be inserted once the last slide is reached which causes a weird animation sight.
You can run the code snippet to have an idea, the animation looks good before 5, but it will be weird after it.
I’ve tried the setTimeout
method but it looks even weird because it just flies over to the right side every time when you click the next button.
// slider
const slides = document.getElementsByClassName("slide"); // this selection is a live collection; any changes in DOM is updated in the variable unlike querySelectors
const btnLeft = document.querySelector(`.btn-left`);
const btnRight = document.querySelector(`.btn-right`);
let currentSlideIndex = 0;
let lastSlideIndex = slides.length - 1;
// go to a slide;
function goToSlide(slideIndex) {
[...slides].forEach((s, i) => {
s.style.transform = `translateX(${110 * (i - slideIndex)}%)`
})
currentSlideIndex = slideIndex;
}
goToSlide(currentSlideIndex);
// make ready the next slide if current slide is the first or the last slide
function readyNextSlide() {
// if currentSlide is the last slide, shift the first slide to the end
if (currentSlideIndex === lastSlideIndex) {
slides[lastSlideIndex].insertAdjacentElement("afterend", slides[0]);
slides[lastSlideIndex].style.transform = `translateX(${110}%)`;
currentSlideIndex--; //this is because current slide is now the second last slide
}
// if currentSlide is the first slide, shift the last slide to the beginning
if (currentSlideIndex === 0) {
slides[0].insertAdjacentElement("beforebegin", slides[lastSlideIndex]);
slides[0].style.transform = `translateX(-${110}%)`;
currentSlideIndex++; //this is because current slide is now the second slide
}
}
// put the last slide in the beginning; ('if' condition is not necessary but providing if condition is future proof if user sets the initial slide to be shown as the last slide )
if (currentSlideIndex === lastSlideIndex || currentSlideIndex === 0) readyNextSlide();
// shift all slides left or right based on direction provided
function shiftSlides(direction) {
direction ? currentSlideIndex++ : currentSlideIndex--
if (currentSlideIndex === lastSlideIndex || currentSlideIndex === 0) readyNextSlide();
goToSlide(currentSlideIndex);
}
//button click events
btnRight.addEventListener("click", shiftSlides.bind(null, 1));
btnLeft.addEventListener("click", shiftSlides.bind(null, 0));
body {
display: grid;
height: 100vh;
width: 100vw;
align-items: center;
align-content: center;
justify-content: center;
}
.slider {
display: flex;
justify-content: center;
position: relative;
width: 600px;
height: 300px;
transform: scale(0.8);
overflow: hidden; /* remove overflow to see what's going on*/
}
.slide {
position: absolute;
width: 50%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
transition: transform 1s;
}
.slide b {
position: absolute;
font-size: 10em;
color: black;
opacity: 0.6;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.s1 {
background-color: cornflowerblue;
}
.s2 {
background-color: bisque;
}
.s3 {
background-color: coral;
}
.s4 {
background-color: thistle;
}
.btn {
position: absolute;
top: 50%;
z-index: 10;
border: none;
background: crimson;
font-family: inherit;
color: white;
height: 5.5rem;
width: 5.5rem;
font-size: 3.25rem;
cursor: pointer;
}
.btn-left {
left: 6%;
transform: translate(-50%, -50%);
}
.btn-right {
right: 6%;
transform: translate(50%, -50%);
}
<div class="slider">
<div class="slide s1"><b>1</b></div>
<div class="slide s2"><b>2</b></div>
<div class="slide s3"><b>3</b></div>
<div class="slide s4"><b>4</b></div>
<div class="slide s4"><b>5</b></div>
<div class="slide s4"><b>6</b></div>
<button class="btn btn-left">←</button>
<button class="btn btn-right">→</button>
</div>