setInterval() Method creating strange overlap
Asked Answered
Q

1

6

As I was playing around trying to build a simple text carousel, I came across an issue I am having a difficult time understanding.

The layout is simple. I have a wrapper and the text I want the carousel to cycle through.

The issue I am having, however, seems as far as I can tell to be coming from the setInterval method. After the animation cycles through all the text and returns to the beginning, there is a strange overlap between the first and second text that is displayed. The first text will animate, but then will return to replace the second text temporarily.

Any help in understanding what is causing this error to render in this way would be greatly appreciated.

let animateSlide = setInterval(moveSlide, 1200);

function moveSlide() {
  let carousel = document.getElementById("wordCarousel");
  let firstSlide = carousel.children[0];
  let createID = document.createAttribute("id");

  createID.value = "active";

  firstSlide.setAttributeNode(createID);

  carousel.appendChild(carousel.firstChild);

  carousel.children[carousel.children.length - 1].removeAttribute("id");
}
/* Carousel Styles */

#wordCarousel {
  height: 36px;
  overflow: hidden;
}

  .carouselSlide {
    color: #555;
    font-size: 36px;
  }

#active {
  margin-top: 0px;
  animation-name: example;
  animation-duration: 1.2s;
  animation-timing-function: ease;
}

@keyframes example {
  from {
    margin-top: 0px;
  }
  to {
    margin-top: -40px;
  }
}
<div id="wordCarousel">
  <div class="carouselSlide">
    Item 1
  </div>
  <div class="carouselSlide">
    Item 2
  </div>
  <div class="carouselSlide">
    Item 3
  </div>
  <div class="carouselSlide">
    Item 4
  </div>

</div>
Quadriplegic answered 15/11, 2020 at 10:32 Comment(0)
Y
7

Don't rely on setInterval when dealing with CSS animation. You will never have a perfect synchronization. Better consider events like animationiteration/animationend/animationstart

Here is a better idea will less of code an easier to handle.

let carousel = document.querySelector('#wordCarousel div');

carousel.addEventListener('animationiteration', () => {
  carousel.appendChild(carousel.children[0]);
});
#wordCarousel {
  height: 36px;
  overflow: hidden;
}

.carouselSlide {
  color: #555;
  font-size: 36px;
  line-height:100%; /* line-height will make sure the height is equal to 36px, font-size alone isn't enough  */
}

#wordCarousel > div {
  height:100%;
  animation: example 1s infinite;
}

@keyframes example {
  to {
    transform: translateY(-100%);
  }
}
<div id="wordCarousel">
  <div>
    <div class="carouselSlide">
      Item 1
    </div>
    <div class="carouselSlide">
      Item 2
    </div>
    <div class="carouselSlide">
      Item 3
    </div>
    <div class="carouselSlide">
      Item 4
    </div>
  </div>
</div>
Yttriferous answered 15/11, 2020 at 11:42 Comment(1)
You're right, that code is much simpler. Thank you for your contribution, it is much appreciated.Quadriplegic

© 2022 - 2024 — McMap. All rights reserved.