6

I want to make an infinite carousel in javascript. When the elements go off-screen, I clone them and paste them at the end of the list. But after a minute there are a lot of cloned elements in the HTML layout. I decided to delete this element after cloning. But I get an instant offset of all elements. How to avoid it? Or maybe there is another algorithm on how to implement this endless carousel?

Here's the code https://codepen.io/alessandro-kex/pen/abGWNEK

window.addEventListener("load", function () {
  const slideContainer = document.querySelector(".carousel");
  const slidesWrapper = document.querySelector(".carousel-slides");
  let slides = document.querySelectorAll(".carousel-slide");
  let index = 0;
  const interval = 1500;
  let moveDistance = 0;
  const paddingRight = 50;
  let lastSlideIndex = slides.length - 1;
  let firstClone;

  const startSlide = (index) => {
    this.setInterval(() => {
      moveDistance = moveDistance + slides[index].clientWidth + paddingRight;
      slidesWrapper.style.transform = `translateX(${-moveDistance}px)`;
      slidesWrapper.style.transition = "1s";

      firstClone = slides[index].cloneNode(true);
      firstClone.id = `first-clone-${index}`;
      slidesWrapper.append(firstClone);
      /*If uncomment it - then the problem starts */
      //slides[index].remove();

      index++;
    }, interval);
  };
  startSlide(index);
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.carousel {
  margin: 0 auto;
  width: 100%;
  position: relative;
}

.carousel-slides {
  display: flex;
  list-style: none;
  gap: 50px;
  flex-shrink: 1;
}

.carousel-slide {
  position: relative;
  min-width: 0;
  flex-shrink: 0;
}

.carousel-slide {
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}

.carousel-item-text {
  white-space: nowrap;
}

.carousel-item-img {
  width: 100px;
  height: auto;
}

.round {
  padding: 30px 50px;
  border-radius: 120px;
}

.light-blue {
  background-color: #d8f1ff;
}

.pink {
  background-color: #ffeaf0;
}

.purpule {
  background-color: #eae9ff;
}
  <div class="carousel">
    <ul class="carousel-slides">
      <li class="carousel-slide" data-number="0">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide light-blue round" data-number="1">
        <span class="carousel-item-text">11111111 1111 <br> 111111111</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide pink round">
        <span class="carousel-item-text">22222 22222 <br> 222222222 2222222222 222222222</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide light-blue round">
        <span class="carousel-item-text">333 333333333 <br> 333333333333</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide purpule round">
        <span class="carousel-item-text">4444 444444444444<br> 44444</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide  pink round">
        <span class="carousel-item-text">55555555 55555<br> 55 5555</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide pink round">
        <span class="carousel-item-text">6666666 6666666666 <br> 66666 6666666 66666</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide  light-blue round">
        <span class="carousel-item-text">777777 777 777<br> 77 77777</span>
      </li>
      <li class="carousel-slide">
        <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
      </li>
      <li class="carousel-slide purpule round" data-number="16">
        <span class="carousel-item-text">888 8888<br> 88888888</span>
      </li>
    </ul>
  </div>

2
  • Can you make a horizontal carousel by using only 2 items? When the first item reaches a certain position to the left, the right goes. Just an idea. Commented Sep 18, 2022 at 15:55
  • Do you mean one item (one slides) or wrapper of the slides? Commented Sep 18, 2022 at 16:15

3 Answers 3

6

My idea is with pure CSS. There are two containers red and blue and they overlap each-other. Here is my draft:image

I have used a=700px which is the width of the containers, and w=500px which is the width of the green wrapper. Hope this would help somebody:)

.wrapper {
        width: 500px;
        overflow-x: hidden;
        border: 2px solid black;
        position: relative;
        height: 100px;
    }
    
    .first {
        width:700px;
        height: 100px;
        background-color: red;
        position: absolute;
        left:0px;
        top:0;
        animation: firstDiv 10s linear infinite;
        
    }
    @keyframes firstDiv {
      0 {left: 0px;}
      15% {left: -200px;}
      50% {left: -700px;}
      65.9% {left: -900px;}
      66% {left: 500px;}
      99.9% {left: 0px;}
      100% {left: 0px;}
    }
    
    .second {
        width:700px;
        height: 100px;
        background-color: blue;
        position: absolute;
        left:700px;
        top:0;
        animation: secondDiv 10s linear infinite;
    }
    @keyframes secondDiv {
      0 {left: 700px;}
      15% {left: 500px;}
      50% {left: 0px;}
      65.9% {left: -200px;}
      66% {left: -200px;}
      99.9% {left: -700px;}
      100% {left: 700px;}
    }
<div class="wrapper">
        <div class="first">first container first container first container first container first container first container first container first container</div>
        <div class="second">second container second container second container second container second container second container second container</div>
     
    </div>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer! I thought to do the slider using the animation, but got the blank space between the sliders during the animation. But I will try to adapt your code to my slider as another variant for the future!
3

For this kind of thing you should familiarize yourself with promises

otherwise the idea is the right one,
1 - make a translateX with a transition time
2 - once the transition is finished remove the transition time
3 - put the first element at the end and reset the translateX to zero
4 - start again...

complete code :

 
(async ()=>   // async IIFE code for slider.
  {
  const
    interval       = 1500  // ms
  , paddingRight   = 50
  , slideContainer = document.querySelector('.carousel') 
  , slidesWrapper  = document.querySelector('.carousel-slides')
  , slides         = document.querySelectorAll('.carousel-slides > li')
  , delay          = ms => new Promise(r => setTimeout(r, ms))
  , movLeft = (el, mov) => new Promise(r =>
    {
    el.ontransitionend =_=>
      {
      el.ontransitionend = null
      el.style.transition = 'none';
      r()
      }
    el.style.transition = '1s';
    el.style.transform  = `translateX(${-mov}px)`;
    });

  let index = 0;

  while (true) // infinite carrousel loop
    {
    await delay( interval )
    await movLeft( slidesWrapper, slides[index].clientWidth + paddingRight  )

    slidesWrapper.appendChild( slides[index] )  // mov first slide to the end
    slidesWrapper.style.transform    = `translateX(0)` // rest translateX
    index = ++index % slides.length
    }
  })()
* {
  margin           : 0;
  padding          : 0;
  box-sizing       : border-box;
  }
.carousel {
  margin           : 0 auto;
  width            : 100%;
  position         : relative;
  }
.carousel-slides {
  display          : flex;
  list-style       : none;
  gap              : 50px;
  flex-shrink      : 1;
  }
.carousel-slide {
  position         : relative;
  min-width        : 0;
  flex-shrink      : 0;
  height           : 100px;
  display          : flex;
  align-items      : center;
  justify-content  : center;
  min-width        : 0;
  }
.carousel-item-text {
  white-space      : nowrap;
  }
.carousel-item-img {
  width            : 100px;
  height           : auto;
  }
.round {
  padding          : 30px 50px;
  border-radius    : 120px;
  }
.light-blue {
  background-color : #d8f1ff;
  }
.pink {
  background-color : #ffeaf0;
  }
.purpule {
  background-color : #eae9ff;
  }
<div class="carousel">
  <ul class="carousel-slides">
    <li class="carousel-slide" data-number="0">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide light-blue round" data-number="1">
      <span class="carousel-item-text">11111111 1111 <br> 111111111</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide pink round">
      <span class="carousel-item-text">22222 22222 <br> 222222222 2222222222 222222222</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide light-blue round">
      <span class="carousel-item-text">333 333333333 <br> 333333333333</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide purpule round">
      <span class="carousel-item-text">4444 444444444444<br> 44444</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide  pink round">
      <span class="carousel-item-text">55555555 55555<br> 55 5555</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide pink round">
      <span class="carousel-item-text">6666666 6666666666 <br> 66666 6666666 66666</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide  light-blue round">
      <span class="carousel-item-text">777777 777 777<br> 77 77777</span>
    </li>
    <li class="carousel-slide">
      <img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
    </li>
    <li class="carousel-slide purpule round" data-number="16">
      <span class="carousel-item-text">888 8888<br> 88888888</span>
    </li>
  </ul>
</div>

new version for multiple carousels... (2022/09/20)

'use strict';

class carouselClass
  {
  static #interval     = 1500;
  static #paddingRight = 50;
  #slidesWrapper;
  #slides;
  #Li_index;
  #onLoop;

  constructor(UL_Carousel) 
    {
    this.#slidesWrapper = UL_Carousel; 
    this.#slides        = UL_Carousel.querySelectorAll(`li`);
    this.#Li_index      = 0;
    this.#onLoop        = false;
    }
  #delay( ms ) 
    {
    return new Promise(resolve => setTimeout(resolve, ms));
    }
  #movLeft( mov, indx )
    {
    return new Promise(resolve =>
      {
      this.#slidesWrapper.ontransitionend =()=>
        {
        this.#slidesWrapper.ontransitionend  = null;
        this.#slidesWrapper.style = '';
        this.#slidesWrapper.appendChild( this.#slides[this.#Li_index] ); // mov slide to the end
        this.#Li_index  = ++this.#Li_index % this.#slides.length;       // next Li element index
        resolve();
        }
      this.#slidesWrapper.style.transition = '1s';
      this.#slidesWrapper.style.transform  = `translateX(${mov}px)`;
      });
    }
  async run() 
    {
    this.#onLoop              = true;
    this.#slidesWrapper.style = '';

    while( this.#onLoop )  // infinite carrousel loop
      {
      await this.#delay( carouselClass.#interval );
      await this.#movLeft( -(this.#slides[this.#Li_index].clientWidth + carouselClass.#paddingRight) );
      } 
    }
  stop()
    {
    this.#onLoop = false;
    }
  }

const carousels = [...document.querySelectorAll('.carousel')]
  .map( cBox =>
  ({ box : cBox
   , cls : new carouselClass( cBox.querySelector('ul.carousel-slides') )
  }))

carousels.index = -1;

carousels.animateNext =_=> 
  {
  carousels.index = ++carousels.index % carousels.length;
  carousels.forEach((crl,i)=> crl.box.classList.toggle('noDisplay', carousels.index !== i) );
  carousels[carousels.index].cls.run();
  }
carousels.animateNext();  // first attempt...

bt_switch.onclick =_=>
  {
  carousels[carousels.index].cls.stop();  // stop infinite loop on current carousel
  carousels.animateNext();
  }
* {
  margin     : 0;
  padding    : 0;
  box-sizing : border-box;
  }
.carousel {
  margin   : 0 auto;
  width    : 100%;
  position : relative;
  overflow : hidden;
  }
.carousel-slides {
  display     : flex;
  list-style  : none;
  gap         : 50px;
  flex-shrink : 1;
  }
.carousel-slides img {
  height: 100px;
  }
.carousel-slides span {
  display        : inline-block;
  white-space    : nowrap;
  padding        : 30px 50px;
  border-radius  : 120px;
  }
.light-blue { background-color : #d8f1ff; }
.pink       { background-color : #ffeaf0; }
.purpule    { background-color : #eae9ff; }

.noDisplay { display : none; }
<div class="carousel">
    <ul class="carousel-slides">
      <li> <img src="https://picsum.photos/150/150?random=1"> </li>
      <li> <span class="light-blue">11111111 1111 <br> 111111111</span></li>
      <li> <img src="https://picsum.photos/150/150?random=2"> </li>
      <li> <span class="pink">2222222 2222 222 <br> 22</span></li>
      <li> <img src="https://picsum.photos/150/150?random=3"> </li>
      <li> <span class="light-blue">33 33 <br> 333 33 33 33 333 33 33 33</span></li>
      <li> <img src="https://picsum.photos/150/150?random=4"> </li>
      <li> <span class="purpule"> 444444 444 44 4<br> 44 44 44 4444  </span></li>
      <li> <img src="https://picsum.photos/150/150?random=5"> </li>
      <li> <span class="pink"> 555555 55 <br>555 555 </span></li>
      <li> <img src="https://picsum.photos/150/150?random=6"> </li>
      <li> <span class="pink"> 66666666666666666666 <br> 6 </span></li>
      <li> <img src="https://picsum.photos/150/150?random=7"> </li>
      <li> <span class="light-blue"> 77777777 777777777  777777<br> 77777777777777777 77777777777777777</span></li>
      <li> <img src="https://picsum.photos/150/150?random=8"> </li>
      <li> <span class="purpule"> 88 888 <br>  8 8 8 8 8</span></li>
    </ul>
  </div>

  <div class="carousel">
    <ul class="carousel-slides">
      <li> <img src="https://picsum.photos/150/150?random=9"> </li>
      <li> <span class="light-blue">aaa <br> 11</span></li>
      <li> <img src="https://picsum.photos/150/150?random=10"> </li>
      <li> <span class="pink">bbb bbb <br> 22</span></li>
      <li> <img src="https://picsum.photos/150/150?random=11"> </li>
      <li> <span class="light-blue">ccc <br> 3</span></li>
      <li> <img src="https://picsum.photos/150/150?random=12"> </li>
      <li> <span class="purpule"> ddd ddd <br> 4  </span></li>
      <li> <img src="https://picsum.photos/150/150?random=13"> </li>
      <li> <span class="pink"> eee eee eee <br> 5 </span></li>
      <li> <img src="https://picsum.photos/150/150?random=14"> </li>
      <li> <span class="pink"> ff ff ff <br> 6 </span></li>
      <li> <img src="https://picsum.photos/150/150?random=15"> </li>
      <li> <span class="light-blue"> g<br> g gg g gg g gg</span></li>
    </ul>
  </div>

  <br><br>
  <button id="bt_switch">___ carousel switcher ___</button>

3 Comments

Could you help me again? I use this slider but with buttons and I write my code for this. I need to insert two sliders on the page and the first slider is display=none when we use mobile. So the problem is that I use the second slider I get in queryselector the first slider's buttons. I think I have to use classes and initialize it somehow. Could you please explain to me in general how to solve this problem? How can I use two sliders simultaneously?
Thank you very much! I understood the idea. But, what if I do not have an opportunity to write different id for sliders? I have to get all sliders in array?!
@MainAdmin I used the html id="..." property for example, all that matters is to be able to have a pointer on each slider; it's up to you to adapt it according to your html
1

You should rather create one carousel and keep all the data in an array with JavaScript. Then by default, on load, display the first element on the array. When the user clicks to view next item on carousel or the time for a certain slide expires, simply call a function to change the slide. For this, initialize a counter to keep track of slide index viewing at the moment and update it whenever the slide is changed. When the user wishes to view the next slide while they are on the last slide, set the counter to 0. Similarly, when the user wishes to view previous slide when they are on the first slide, set the counter to n-1 where n is the number of slides that you offer.

2 Comments

Yes, this is a standard situation with a basic slider. But I have some sort of marquee element. And my slider is placed all the width of the screen. And if I do what you say, my left elements just jump quickly to the start and it will be noticeable.
I think I have just started understanding how to do that. But I can not get the width of my slider container. It overflows over the screen and I try to use clientWidth, but get only screen width! How can I get the width?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.