This article will discuss the best ways to make moving marquee elements in modern web design.
A marquee is an infinite section of text and/or visual element (like images) that automatically scrolls horizontally.
Despite the official HTML <marquee> element being depreciated and strongly discouraged from being used, the overall effect of scrolling, continuous elements used to spice up a webpage is alive and well in 2025, appearing in many trendy websites.
Some still even use the Marquee element, which is still supported by all browsers despite (again) being discouraged from being used. For example, here's the classic bouncing DVD "screensaver" created with a HTML marquee.
This isn't smart, but it still works. The reasons to avoid using this element in 2025 are clear:
However, we've always been fans of marquees at Isotropic.
Take a look at many of the trendy Awwwards websites and you'll see text, images or a combination of both moving horizontally, like so:
This Is A Demo Marquee
Of course, it's never a good idea to put mission critical information in scrolling or animated sections. But for something like the example above, it looks cool, differentiates the site, and makes it memorable. Use it wisely and in moderation.
Marquees are so cool, we even published a helpful tool that will automatically generate a "ticker" style section of scrolling text using CSS box shadows. It's cool, but I think that the approach discussed in this article is even better.
The code to make that marquee demo is sourced from this CodePen by Ryan Mulligan, which is (likely) the best way to make a marquee effect in 2025. He also writes about this code in his blog, https://ryanmulligan.dev/blog/css-marquee.
It's accessible (supports prefers-reduced-motion), infinite, allows for any type of html element, and is lightweight and easy to implement.
It's also made with 100% CSS and no JS.
<div class="marquee"> <div class="marquee__group"> <img src='https://images.unsplash.com/photo-1548199973-03cce0bbc87b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1583511666445-775f1f2116f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1586917383423-c25e88ac05ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1560743173-567a3b5658b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1603232644140-bb47da511b92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> <div aria-hidden="true" class="marquee__group"> <img src='https://images.unsplash.com/photo-1548199973-03cce0bbc87b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1583511666445-775f1f2116f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1586917383423-c25e88ac05ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1560743173-567a3b5658b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1603232644140-bb47da511b92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> </div> <div class="marquee marquee--borders" style="--duration: 100s"> <div class="marquee__group"> <p>The Dogs of Unsplash</p> <p aria-hidden="true">The Dogs of Unsplash</p> <p aria-hidden="true">The Dogs of Unsplash</p> </div> <div aria-hidden="true" class="marquee__group"> <p>The Dogs of Unsplash</p> <p>The Dogs of Unsplash</p> <p>The Dogs of Unsplash</p> </div> </div> <div class="marquee marquee--reverse"> <div class="marquee__group"> <img src='https://images.unsplash.com/photo-1546421845-6471bdcf3edf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1518378188025-22bd89516ee2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1571772805064-207c8435df79?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1602067340370-bdcebe8d1930?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1508948956644-0017e845d797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> <div aria-hidden="true" class="marquee__group"> <img src='https://images.unsplash.com/photo-1546421845-6471bdcf3edf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1518378188025-22bd89516ee2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1571772805064-207c8435df79?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1602067340370-bdcebe8d1930?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1508948956644-0017e845d797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> </div>
@import url("https://fonts.googleapis.com/css2?family=Corben:wght@700&display=swap"); * { box-sizing: border-box; } body { min-height: 100vh; } body { --space: 2rem; display: grid; align-content: center; overflow: hidden; gap: var(--space); width: 100%; font-family: "Corben", system-ui, sans-serif; font-size: 1.5rem; line-height: 1.5; } .marquee { --duration: 60s; --gap: var(--space); display: flex; overflow: hidden; user-select: none; gap: var(--gap); transform: skewY(-3deg); } .marquee__group { flex-shrink: 0; display: flex; align-items: center; justify-content: space-around; gap: var(--gap); min-width: 100%; animation: scroll var(--duration) linear infinite; } @media (prefers-reduced-motion: reduce) { .marquee__group { animation-play-state: paused; } } .marquee__group img { max-width: clamp(10rem, 1rem + 28vmin, 20rem); aspect-ratio: 1; object-fit: cover; border-radius: 1rem; } .marquee__group p { background-image: linear-gradient( 75deg, hsl(240deg 70% 49%) 0%, hsl(253deg 70% 49%) 11%, hsl(267deg 70% 49%) 22%, hsl(280deg 71% 48%) 33%, hsl(293deg 71% 48%) 44%, hsl(307deg 71% 48%) 56%, hsl(320deg 71% 48%) 67%, hsl(333deg 72% 48%) 78%, hsl(347deg 72% 48%) 89%, hsl(0deg 73% 47%) 100% ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .marquee--borders { border-block: 3px solid dodgerblue; padding-block: 0.75rem; } .marquee--reverse .marquee__group { animation-direction: reverse; animation-delay: calc(var(--duration) / -2); } @keyframes scroll { 0% { transform: translateX(0); } 100% { transform: translateX(calc(-100% - var(--gap))); } }
Let's take a look at how this was created and why it's so great.
Here's an overview, before we look at all the code:
style="--duration: 100s"
and for direction, we use a class of .marquee--reverse
..marquee
and the inner content with .marquee__group
.It's really well done, and (imo) should be the standard way a marquee effect is implemented in 2025.
Here's the HTML:
In the demo we can see three marquees. The first and third are reversed with the class of .marquee--reverse
. They have a standard speed, and contain images.
The second (middle one) is all text, and implements borders with a custom class. It also has a slower duration set by the style attribute: style="--duration: 100s"
.
You'll also notice that there are essentially duplicates within the .marquee
div, which are the same except with an aria tag.
This is to make the animation seamlessly infinite, while also being able to adapt to different viewport ratios (more on this when we look at the CSS).
This is made accessible with aria-hidden="true"
, which removes the duplicate content from the accessibility tree.
Also, the images are served directly from Unsplash. You may find this resource interesting: How To Generate Random Images By URL (Web Dev)
All in all, it's an elegant, simple HTML structure.
Now let's look at CSS ✨
And here's the CSS (pulled directly from the CodePen):
We can see the following:
animation: scroll var(--duration) linear infinite;
" line in .marquee__group
. The animation is infinite, linear, and named scroll. The root duration is controlled by the --duration
variable, which can be overwritten to control the speed of a specific group in the HTML markup (mentioned above).animation-direction: reverse;
' in the .marquee--reverse .marquee__group
class.Basically, it does everything really well, and is the best way to implement a scrolling marquee-like effect in 2025.
To implement, you simply add the HTML to your page, swap out the text/images, and add the CSS to your global styles.
You can play with the variables, but realistically this is pretty plug and play... there's not much you need to change!
Ryan Mulligan's code looks to be almost identical to my CSS marquees created around a year ago and used in a load of high profile websites like Mr Beast's official online store :/