Introduction to the modern marquee
The HTML <marquee> element has been deprecated for years, but the need to create infinite scrolling is still very present in modern web design. Whether to display client logos, a news banner or decorative text, the marquee remains a popular UI pattern.
In this complete tutorial, we'll explore several modern CSS techniques to create smooth, performant and accessible marquees. No JavaScript is required for basic animations, and we'll see how to add advanced interactions.
The secret of a perfect infinite marquee lies in content duplication. By doubling the elements, we create a seamless loop where the end meets the beginning with no visible jump.
CSS infinite animation technique
The foundation of any modern marquee relies on @keyframes and the animation property. The idea is simple: move a container from 0% to -50% of its total width, then restart instantly.
Basic HTML structure
The structure consists of three levels: a container with overflow: hidden, an animated track, and the elements to display. Here is the minimal structure:
<!-- Container with overflow hidden -->
<div class="marquee-container">
<!-- Piste animee -->
<div class="marquee">
<!-- Group 1: original content -->
<div class="marquee-track">
<div class="marquee-item">Item 1</div>
<div class="marquee-item">Item 2</div>
<div class="marquee-item">Item 3</div>
</div>
<!-- Group 2: copy for the loop -->
<div class="marquee-track" aria-hidden="true">
<div class="marquee-item">Item 1</div>
<div class="marquee-item">Item 2</div>
<div class="marquee-item">Item 3</div>
</div>
</div>
</div>
Basic CSS for the animation
The CSS that makes the magic work is surprisingly simple. The animation moves the container from its initial position to -50% (half of its total width, which is exactly the size of the duplicated content):
.marquee-container {
overflow: hidden;
width: 100%;
}
.marquee {
display: flex;
width: max-content;
animation: marquee-scroll 25s linear infinite;
}
.marquee-track {
display: flex;
gap: 24px;
padding: 0 12px;
}
@keyframes marquee-scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
Content duplication for seamless loop
The duplication principle is essential for creating a perfect loop. When the animation reaches -50%, the duplicated content is exactly at the position where the original content was at the start. The reset to 0% is therefore invisible.
If you have 6 items and you duplicate them, you have 12 items in total. By moving -50%, you traverse exactly the first 6 items, and at the moment of reset, the next 6 (identical ones) take their place. The transition is invisible because the content is identical.
For accessibility, add aria-hidden="true" on the duplicated group. Screen readers will thus read the content only once.
Logo marquee (clients, partners)
The most frequent use case: displaying a list of client, partner or technology logos. Here is a complete implementation with a modern style:
.logo-item {
display: flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
font-weight: 600;
white-space: nowrap;
transition: all 0.3s ease;
}
.logo-item:hover {
background: rgba(99, 102, 241, 0.1);
border-color: rgba(99, 102, 241, 0.3);
}
/* Fade effect on edges */
.marquee-fade {
position: relative;
}
.marquee-fade::before,
.marquee-fade::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
width: 100px;
z-index: 2;
pointer-events: none;
}
.marquee-fade::before {
left: 0;
background: linear-gradient(90deg, var(--bg-card), transparent);
}
.marquee-fade::after {
right: 0;
background: linear-gradient(-90deg, var(--bg-card), transparent);
}
Text marquee (news ticker)
The text marquee is ideal for news banners, announcements or decorative elements. You can play with typography to create impressive visual effects.
Large format decorative text
An XXL text with gradient effect scrolling in the background, perfect for hero sections or page dividers:
.text-marquee {
display: flex;
gap: 48px;
}
.text-marquee-item {
font-size: 4rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.05em;
white-space: nowrap;
/* Gradient text */
background: linear-gradient(135deg, #6366f1, #8b5cf6, #d946ef);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.text-marquee-separator {
font-size: 4rem;
color: #6366f1;
opacity: 0.5;
}
News ticker with badges
A professional news banner with colored badges to categorize information:
.ticker-marquee {
background: rgba(99, 102, 241, 0.1);
border-top: 1px solid rgba(99, 102, 241, 0.2);
border-bottom: 1px solid rgba(99, 102, 241, 0.2);
padding: 12px 0;
}
.ticker-item {
display: flex;
align-items: center;
gap: 12px;
padding: 0 24px;
white-space: nowrap;
}
.ticker-badge {
padding: 4px 10px;
background: #6366f1;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
}
.ticker-badge.new { background: #10b981; }
.ticker-badge.hot { background: #ef4444; }
.ticker-badge.update { background: #f59e0b; }
Pause on hover
An essential feature for UX: pausing the scroll when the user hovers over the marquee. This allows reading the content comfortably.
Add a slight visual change on hover (opacity, background color) to indicate to the user that the marquee is interactive and can be paused.
The implementation is very simple thanks to animation-play-state:
/* Pause animation on container hover */
.marquee-container:hover .marquee {
animation-play-state: paused;
}
/* Or directly on the animated element */
.marquee:hover {
animation-play-state: paused;
}
/* Optional visual feedback */
.marquee-container:hover {
background: rgba(99, 102, 241, 0.05);
}
Reverse direction and variable speeds
To create interesting visual compositions, combine multiple marquees with different directions and speeds. The horizontal parallax effect is very effective for giving depth.
Reversed direction
Use animation-direction: reverse to reverse the scroll direction:
/* Reversed direction */
.marquee-reverse {
animation-direction: reverse;
}
/* Vitesses differentes */
.marquee-slow {
animation-duration: 40s;
}
.marquee-fast {
animation-duration: 15s;
}
/* Default speed */
.marquee {
animation-duration: 25s;
}
/* Combine for parallax effect */
.marquee-layer-1 { animation-duration: 30s; }
.marquee-layer-2 { animation-duration: 20s; animation-direction: reverse; }
.marquee-layer-3 { animation-duration: 25s; }
Content-adaptive speed
For a constant speed regardless of the content quantity, calculate the duration based on the width:
// Speed in pixels per second
const SPEED = 50; // px/s
function setMarqueeSpeed(marquee) {
const track = marquee.querySelector('.marquee-track');
const width = track.offsetWidth;
const duration = width / SPEED;
marquee.style.animationDuration = `${duration}s`;
}
// Apply to all marquees
document.querySelectorAll('.marquee').forEach(setMarqueeSpeed);
Responsive and accessibility
A good marquee must be adaptive and accessible. Here are the best practices to follow for an optimal experience on all devices and for all users.
Responsive design
Adapt the element size and speed according to screen size:
/* Mobile: smaller elements, reduced speed */
@media (max-width: 768px) {
.marquee {
animation-duration: 35s;
}
.logo-item {
padding: 12px 20px;
font-size: 0.9rem;
}
.text-marquee-item {
font-size: 2.5rem;
}
.marquee-track {
gap: 16px;
}
}
/* Very wide screens: increased speed */
@media (min-width: 1920px) {
.marquee {
animation-duration: 20s;
}
}
Accessibility
Accessibility is crucial. Respect user preferences for animations:
/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
.marquee {
animation: none;
}
/* Display content statically */
.marquee-track[aria-hidden="true"] {
display: none;
}
.marquee-container {
overflow-x: auto;
}
}
/* Hide duplicated content from screen readers */
.marquee-track[aria-hidden="true"] {
/* Already handled by aria-hidden="true" */
}
/* Visible focus for keyboard navigation */
.logo-item:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
}
Continuously moving animations can cause problems for people with vestibular disorders. Always respect prefers-reduced-motion and provide a way to stop the animation.
Performance
A few tips for performant marquees:
- Use
transforminstead ofleftormarginfor the animation - this triggers GPU compositing - Add
will-change: transformto prepare the browser for the animation - Avoid too many elements in the same marquee - merge SVGs if possible
- Limit the number of marquees animated simultaneously on the page
.marquee {
/* Optimisation performance */
will-change: transform;
backface-visibility: hidden;
perspective: 1000px;
}
/* Disable will-change after animation */
.marquee.loaded {
will-change: auto;
}
Conclusion
The modern CSS marquee is a powerful tool for adding movement and visual interest to your pages. By mastering the duplication technique and animation properties, you can create smooth and professional scrolling effects.
Key points to remember:
- Duplicate the content for a perfect seamless loop
- Use
translateX(-50%)for the animation - Add pause on hover for better UX
- Respect
prefers-reduced-motionfor accessibility - Combine directions and speeds for creative effects
Find ready-to-use and customizable marquees in our effects library, with one-click copyable code.