Метод setInterval(), создающий странное перекрытие частей текста
При моей попытке построить простую текстовую карусель, я столкнулся с проблемой, которую трудно понять.
Макет простой. У меня есть оболочка и текст, который я хочу, чтобы карусель перебирала.
Однако проблема, с которой я столкнулся, насколько я могу судить, исходит от метода setInterval.
После того, как анимация проходит по всему тексту и возвращается к началу, появляется странное перекрытие между первым и вторым отображаемым текстом.
Первый текст будет анимирован, но затем вернется, чтобы временно заменить второй текст.
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>
Любая помощь в понимании того, что вызывает эту ошибку, будет принята с благодарностью.
Свободный перевод вопроса setInterval() Method creating strange overlap от участника @Just Trying to Learn JS.
Ответы (1 шт):
Не полагайтесь на setInterval при работе с CSS-анимацией. У вас никогда не будет идеальной синхронизации. Лучше учитывать такие события, как animationiteration / animationend / animationstart
Вот лучшая идея: меньше кода будет легче обрабатывать.
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 гарантирует, что высота равна 36px, одного font-size недостаточно */
}
#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>
Свободный перевод ответа от участника @Temani Afif.