marquee
Although the marquee element was never accepted as a standard, people loved using it on their websites. It could be easily implemented and offered a bit of fun, way before CSS animations were a thing. Marquee
was often used for under-construction pages or websites with headlines. Text or images moving across the screen served as a successful attention grabber.
You may be asking yourself why the marquee
element gets a wave of attention now, in 2022. As the Y2K trend has a revival within fashion, brands also want to bring retro vibes and aesthetics to their websites. What better markets ultra-low-rise jeans than a website with blinking, colourful images and moving text? Well, you probably have guessed it: a website that uses modern user experience and accessibility practices to be enjoyable for everyone. Moving content grabs your attention, but it is also very distracting. Surfing the web should be a pleasant experience for every individual.
marquee
Although moving text at high speed over a screen may sound compelling to try out the marquee
element in your next web project, you really shouldn't. Here are some reasons for you if you are not convinced yet:
The usage of the marquee
element is no longer recommended. It is officially marked as deprecated, meaning modern browsers might still support it for compatibility purposes. However, the element could be removed anytime, and newer or better alternatives are available. So, it should definitely not be used anymore.
The marquee
element was launched without ever being tested properly, specifically regarding accessibility. This resulted in issues for people with visual impairments and cognitive disabilities. In addition, the element doesn't clearly define what its content is. It can be just text, an image, a link or something else. When assistive devices like screen readers don't know how to announce a website's content, their users might miss it or don't understand its purpose.
Automatically scrolling text can be unreadable by some people and severely distracting. Especially users with attention deficits have a hard time concentrating on other parts of the website when some content is moving or blinking. Some users also experience nausea from animated content. Such content can also cause problems for people using assistive technology to surf the web. These problems occur regardless of scrolling speed.
The latest version of the Web Content Accessibility Guidelines (WCAG 2.2) clearly presents recommendations to avoid the distraction of users during their interaction with a website. The success criterion 2.2.2 states that moving, blinking and scrolling information needs a mechanism to be paused or stopped. This rule applies if the animation:
This requirement is Level A, meaning it is the minimum level of accessibility. Many users with disabilities will find it very difficult or impossible to access information. All websites should at least satisfy the minimum accessibility criteria.
The human eye is attracted to movement. As the content within the marquee
element is constantly moving, it can be distracting for anybody, not just people with disabilities. Therefore using the marquee element results not only in accessibility but also in usability problems on a website.
When text inside a marquee
element contains a link, additional problems occur. Clicking on a moving link is more complicated than clicking on static text. Depending on the speed and length of the scrolling text, some users may be unable to do so.
Users can also have difficulties printing a website if its content is not always fully visible. When multiple attempts are needed to complete the printing task, it makes it very inefficient, if not impossible.
If you still want to get the "marquee aesthetic", there is a way without using the element. CSS animations are a more suitable method. Creating the scrolling effect with CSS needs a bit more code to implement than using a single line of HTML. However, CSS is still the recommended practice as it is used to style content and create presentational effects, whereas HTML is not. In addition, CSS can be used to create more powerful and advanced animations. So let's get right into it.
marquee
elementAs a first step, we choose a standard HTML element instead of the marquee
element. Depending on the type of content we want to animate, a different HTML element will be appropriate.
For the first example, we want to animate text. Therefore, we use the p
element. We wrap this element inside a div
container and add a class called marquee-alternative
. This class name is arbitrary and was just added to style and animate our fake marquee with CSS later.
<div class="marquee-alternative">
<p>Newsflash: JLo and Ben Affleck got married!</p>
</div>
The classic HTML marquee
element typically moves across the screen's whole width. To recreate this original effect for our fake marquee element, we first set the overflow
to hidden
on the div
container, which has the class marquee-alternative
. This makes sure that no unwanted vertical scrolling is possible. We also assure the container has a width
of 100%
.
.marquee-alternative {
overflow: hidden;
width: 100%;
}
The p
element inside the marquee-alternative
container needs some basic styling as well. To remove all unwanted default spacing of the p
element, we set the margin
to 0
. We also set the width
to fit-content
. This assures that the p
element has the length of its content. This is important as we want the text of our fake marquee element to loop through without any delay. If the p
element had the whole width of the screen (100%), there would be a few seconds where our marquee text is not visible after it left the screen.
.right-to-left p {
margin: 0;
width: fit-content;
}
We can use CSS animations to move our fake marquee element over the screen. To create an animation, we use the@keyframes
directive. Our custom animation called marquee-right-to-left
starts at 100vw
(far right) and ends at -100%
(far left). This means that our fake marquee begins outside the screen on the right side and moves to the left, ending outside the screen as well.
@keyframes marquee-right-to-left{
from {
transform: translateX(100vw);
}
to {
transform: translateX(-100%);
}
}
You may wonder why we use 100vw
as the start value and not 100%
. This is because we previously set the width of the p
element to fit its content. If we used 100%
as a start value, the animation would not start outside of the screen but somewhere else, depending on the content length.
Note: If you implement your fake marquee element and it is not supposed to move across the whole screen width, you must adapt the 100vw
value to your use case.
To start our keyframe animation, we add some animation properties to our p
element. We refer to our marquee-right-to-left
keyframe by setting the animation-name
. We also specify an animation-duration
of 20 seconds, linear
movement and infinite
repetitions. Depending on your desired marquee aesthetic, you can adapt these values to change the animation style according to your needs.
The shortened version of adding our CSS animation would be animation: marquee-right-to-left 20s linear infinite;
instead of writing the 4 separate properties.
.marquee-alternative p {
margin: 0;
width: fit-content;
animation-name: marquee-right-to-left;
animation-duration: 20s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
Newsflash: JLo and Ben Affleck got married!
Now our fake marquee element should work, just like the old HTML classic. But wait, we are not finished yet!
Some measures can be taken to make our fake marquee element more accessible and user-friendly.
The prefers-reduced-motion
media query can be used to stop all animations for users that don't want them. As it is hard to decide when an animation is slow enough for people with disabilities, the best practice is to pause them entirely. In our case, we use the prefers-reduced-motion
media query to only enable the animation if a user has no other preferences set.
We remove the animation
property from the .marquee-alternative p
nested class above and wrap it inside the media query.
.marquee-alternative p {
margin: 0;
width: fit-content;
/* animation got removed here */
}
/* Only shows animation for users that have set no motion preference */
@media (prefers-reduced-motion: no-preference) {
/* animation is added here */
.marquee-alternative p{
animation: marquee-right-to-left 20s linear infinite;
}
}
There are two different ways to pause the marquee
animation. We can add a pause/play button
or stop the animation on hover
. Adding a button
would be a cleaner and more accessible option. However, some projects may not allow adding an extra button
. That is when we use the hover
alternative with the help of a media query.
To ease the reading act and fight the issue of chasing moving text, we pause the animation when a user hovers over the marquee container (the div
) or sets the focus on it. This is done by setting the animation-play-state
to paused
for the p
element, on hover
and focus
of the div
.
/* Pause animation on hover and on focus */
.marquee-alternative:hover p,
.marquee-alternative:focus p{
animation-play-state: paused;
}
Newsflash: JLo and Ben Affleck got married!
To comply with the previously named WCAG criterion 2.2.2, we add a play and pause button for the animation. Not every user has set their motion preferences to reduce
. We still want to allow everybody to pause the animation if it is perceived as too distracting.
Note: When you implement the pause/play button, remove the animation-play-state: pause
from the previous step. Otherwise, it would confuse users why the text is paused although they haven't pressed the button yet.
As a first step, we wrap our existing marquee-alternative
container into another div
and assign it the class marquee-container
. We then add a button
element to start and stop the animation. It has the class btn
and the aria-pressed
state set to false
. The p
element gets the class marquee-content
assigned to it. We also add the animation-play-state
style to the p
element to be able to change it later on with JavaScript.
<div class="marquee-container">
<div class="marquee-alternative">
<p class="marquee-content" style="animation-play-state: running;">Newsflash: JLo and Ben Affleck got married!</p>
</div>
<button type="button" class="btn" aria-pressed="false">Pause</button>
</div>
Now we add a little bit of styling to the new HTML elements. This CSS code is added in addition to the already existing styling from before.
The .marquee-container
gets a border
and flex
position. All elements inside the container are aligned in its centre. The .marquee-content
, which is our text, gets some styling as well.
.marquee-container {
display: flex;
align-items: center;
border: 3px solid #000;
}
.marquee-content {
margin: 0;
width: fit-content;
}
The button
gets a basic styling by changing the background-color
, border
, box-shadow
, cursor
and padding
. Make sure to add enough padding
that the button
has a minimum size of 48x48 px. This is the minimum click area a button
should have to be accessible. Hover
and focus
styles are added to have a more apparent visual change when interacting with the button. We also change the visual appearance of the button
when it gets pressed by styling it when aria-pressed
is set to true
.
.btn {
cursor: pointer;
background-color: #fff;
border: 0;
border-left: 3px solid #000;
padding: 1.1rem 1rem;
box-shadow: 0 0.5rem 0.5rem -0.125rem #0005;
}
.btn:hover,
.btn:focus-visible,
.btn[aria-pressed="true"]:hover {
color: #fff;
background-color: #000;
}
.btn[aria-pressed="true"] {
box-shadow: 0 0.5rem 0.5rem -0.125rem inset #0005;
}
For the JavaScript part of this implementation, we first query the marquee-content
(p
element) and the button
with the help of document.querySelector
and save them into variables. This is done to make the code more readable.
let marqueeText = document.querySelector(".marquee-content");
let button = document.querySelector(".btn");
We then add an event listener for the click
event of the button
. When the button
is clicked, we check if the animation is currently running by looking at the animationPlayState
. If it is running
, we stop the animation by setting the state to paused
. We also change the button.innerText
and set ariaPressed
to true
. As the button
serves as a pause and play button, we also add the functionality of enabling the animation again after it was stopped. This is done by setting the animationPlayState
back to running
and changing the button.innerText
and ariaPressed
state again.
button.addEventListener("click", () => {
const isRunning = marqueeText.style.animationPlayState == "running";
// change behaviour of animation and button
if (isRunning) {
// stop the animation
marqueeText.style.animationPlayState = "paused";
// change button text
button.innerText = "Play";
button.ariaPressed = "true";
} else {
// start the animation
marqueeText.style.animationPlayState = "running";
// change button text
button.innerText = "Pause";
button.ariaPressed = "false";
}
});
Newsflash: JLo and Ben Affleck got married!
Your fake marquee element can now be stopped and activated again with the click of a button. This allows users to decide for themselves if they want to see the scrolling content on the screen or not.
Using the marquee aesthetic is a fun way of animating web content and grabbing a user's attention. But please be aware of the marquee
element's impact on people. Even if the desired retro aesthetic is achieved without using the actual element but the presented alternative, the same named usability and accessibility concerns remain. So if you implement scrolling, animated content on your website, be conscious of its downsides and take measures to make the experience more accessible.
Daniela Kubesch is a frontend developer from Austria who is passionate about accessibility and inclusive design. She strongly believes in equality and inclusion. Daniela is co-founder of a11yphant.com, a platform that teaches the basics of web accessibility.
Website/blog: dnikub.dev
Twitter: @dnikub
Mastodon: uiuxdev.social/@dnikub
LinkedIn: danikubesch