A marquee that never jumps
CaveatThe track holds the list twice and travels exactly -50%. Any other distance, or a single copy, and the loop visibly snaps back at the seam.
FallbackMark the second copy aria-hidden — it is decoration, and a screen reader should not read the same list twice. Stop the animation under prefers-reduced-motion.
.track {
display: flex;
width: max-content; /* the list, twice */
animation: slide 14s linear infinite;
}
@keyframes slide {
to { transform: translateX(-50%); }
}
Published
Questions
Why does my infinite marquee jump at the end of each loop?
The travel and the content have to agree. Hold the list twice in the track and animate exactly -50%: at that point the second copy sits precisely where the first started, so resetting to 0 is invisible. Any other distance, or a single copy, and the seam shows.
Why is the scroll uneven?
A default timing function eases in and out of every iteration, which reads as a stutter on a continuous loop. linear is the only correct choice here.
How should a marquee behave for screen readers and reduced motion?
Mark the duplicate aria-hidden — it is decoration, and nobody should hear the same list twice. Then stop the animation under prefers-reduced-motion: a permanent horizontal crawl is exactly what that preference is asking you not to do.