<marquee> elements are deprecated and must not be used

Scrolling <marquee> text keeps moving and cannot be paused, so customers with reading difficulties, attention disorders or low vision cannot read the offer or shipping message it contains. The movement also distracts from the products and the checkout.

Rule id
marquee
Source
axe-core 4.13.0
Impact
Serious
Fix tier
AUTO
on Shopify, Shopware, WooCommerce and Magento
Status
runs

What the check does

Ensure <marquee> elements are not used

The rule selects every <marquee> element on the page, hidden ones included, and fails each one that is visible on screen. It does not read the element’s attributes or its text, so the speed, the direction and whether the text actually moves play no part.

A <marquee> passes only when axe-core finds it hidden from view, for example when it or an ancestor has display: none or opacity: 0, when it has visibility: hidden, when clip-path: inset(50%) or a zero-size clip hides it, or when it is positioned above the top of the page. One further down a long page still counts as visible.

Validiscan’s scanner loads each page at 1440 by 900 pixels (desktop) and 390 by 844 (mobile) by default, so a <marquee> the theme hides at one size is reported only for the other. Moving text built with CSS animation or JavaScript is outside this rule.

How to fix it

Remove the <marquee> element and show its text as static content. If a moving announcement bar is wanted, build it with CSS that respects prefers-reduced-motion and give it a visible pause control.

WCAG success criteria

EN 301 549 clauses

The EN 301 549 clause of each criterion, by version of the standard
WCAG criterion Version 3.2.1 Version 4.1.1
2.2.2 9.2.2.2 9.2.2.2

Where a recipe fixes it

Show the before and after (1)
Before and after Example data

sections/announcement-bar.liquid Changes to sections/announcement-bar.liquid: 2 added, 2 removed

Changes to sections/announcement-bar.liquid: 2 added, 2 removed
Line before Line after Change Code
3 3 -%}
4 4 <div class="announcement-bar color-accent"{% if bar_lang != '' %} lang="{{ bar_lang }}"{% endif %}>
5 5 <div class="page-width">
6 Removed <marquee class="announcement-bar__message" behavior="scroll" direction="left" scrollamount="4">{{ section.settings.text | escape }}</marquee>
7 Removed <p class="announcement-bar__note"><blink class="announcement-bar__flag">New</blink> winter collection</p>
6 Added <div class="announcement-bar__message">{{ section.settings.text | escape }}</div>
7 Added <p class="announcement-bar__note"><span class="announcement-bar__flag">New</span> winter collection</p>
8 8 </div>
9 9 </div>
10 10
Show the before and after (1)
replaces a seeded marquee and blink in the top bar; axe no longer reports them Example data

Resources/views/storefront/layout/header/top-bar.html.twig Changes to Resources/views/storefront/layout/header/top-bar.html.twig: 2 added, 2 removed

Changes to Resources/views/storefront/layout/header/top-bar.html.twig: 2 added, 2 removed
Line before Line after Change Code
4 4 {% block layout_header_top_bar_usp %}
5 5 <p class="top-bar-usp">
6 6 {% sw_icon 'checkmark' style { size: 'xs' } %}
7 Removed <marquee class="top-bar-marquee" behavior="scroll" scrollamount="4"><span>{{ 'header.topBarUsp'|trans }}</span></marquee>
7 Added <span class="top-bar-marquee"><span>{{ 'header.topBarUsp'|trans }}</span></span>
8 8 </p>
9 9 {% endblock %}
10 10
13 13 <li class="top-bar-nav-item">
14 14 <a class="top-bar-nav-link top-bar-help" href="{{ url('/contact') }}">
15 15 {% sw_icon 'headset' style { size: 'xs' } %}
16 Removed <blink class="top-bar-blink">{{ 'header.topBarHelp'|trans }}</blink>
16 Added <span class="top-bar-blink">{{ 'header.topBarHelp'|trans }}</span>
17 17 </a>
18 18 </li>
19 19 </ul>
Show the before and after (2)
makes a marquee and a blink added to the fixture theme static Example data

footer.php Changes to footer.php: 1 added, 1 removed

Changes to footer.php: 1 added, 1 removed
Line before Line after Change Code
31 31 <?php endfor; ?>
32 32 </div>
33 33
34 Removed <marquee class="kb-ticker" behavior="scroll" scrollamount="3"><?php esc_html_e( 'Free returns within 30 days', 'kestrel-birch' ); ?></marquee>
34 Added <div class="kb-ticker"><?php esc_html_e( 'Free returns within 30 days', 'kestrel-birch' ); ?></div>
35 35 <div class="site-info">
36 36 <?php // VALIDISCAN-SEED color-contrast: .site-info and the footer copy are #888 on #f4f1ec (3.1:1), see main.css. ?>
37 37 <p>

functions.php Changes to functions.php: 1 added, 1 removed

Changes to functions.php: 1 added, 1 removed
Line before Line after Change Code
223 223 */
224 224 function kb_single_product_usp() {
225 225 // VALIDISCAN-SEED vs-reflow: .kb-usp is white-space: nowrap in assets/css/woocommerce.css.
226 Removed echo '<p class="kb-usp"><blink class="kb-new">' . esc_html__( 'New', 'kestrel-birch' ) . '</blink> ' . esc_html__( 'Same-day dispatch · Free returns · Climate-neutral delivery', 'kestrel-birch' ) . '</p>';
226 Added echo '<p class="kb-usp"><span class="kb-new">' . esc_html__( 'New', 'kestrel-birch' ) . '</span> ' . esc_html__( 'Same-day dispatch · Free returns · Climate-neutral delivery', 'kestrel-birch' ) . '</p>';
227 227 }
228 228 add_action( 'woocommerce_single_product_summary', 'kb_single_product_usp', 31 );
229 229
turns blink and marquee into static elements in templates and PHP strings Example data

functions.php Changes to functions.php: 1 added, 1 removed

Changes to functions.php: 1 added, 1 removed
Line before Line after Change Code
11 11 add_action( 'after_setup_theme', 'minimal_setup' );
12 12
13 13 function minimal_sale() {
14 Removed echo '<p><blink class="sale">' . esc_html__( 'Sale', 'minimal' ) . '</blink></p>';
14 Added echo '<p><span class="sale">' . esc_html__( 'Sale', 'minimal' ) . '</span></p>';
15 15 }

template-parts/notice.php Changes to template-parts/notice.php: 3 added, 3 removed

Changes to template-parts/notice.php: 3 added, 3 removed
Line before Line after Change Code
1 1 <div class="notice">
2 Removed <marquee class="notice__ticker" behavior="scroll" direction="left" scrollamount="4">
2 Added <div class="notice__ticker">
3 3 <?php esc_html_e( 'Free shipping this week', 'minimal' ); ?>
4 Removed </marquee>
5 Removed <blink><?php esc_html_e( 'New!', 'minimal' ); ?></blink>
4 Added </div>
5 Added <span><?php esc_html_e( 'New!', 'minimal' ); ?></span>
6 6 </div>
Show the before and after (1)
makes an added ticker static and validates Example data

app/design/frontend/Validiscan/fixture/Magento_Cms/content/home.html Changes to app/design/frontend/Validiscan/fixture/Magento_Cms/content/home.html: 2 added, 2 removed

Changes to app/design/frontend/Validiscan/fixture/Magento_Cms/content/home.html: 2 added, 2 removed
Line before Line after Change Code
1 Removed <marquee class="news-ticker" behavior="scroll" direction="left" scrollamount="4">
1 Added <div class="news-ticker">
2 2 <p>Autumn sale: 20% off all jackets</p>
3 Removed </marquee>
3 Added </div>
4 4 <!-- VALIDISCAN-SEEDED vs-carousel + vs-motion + aria-hidden-focus: Page Builder slider autoplays (data-autoplay and a CSS animation) with no pause control; hidden slides keep focusable links; dots have no names -->
5 5 <div
6 6 class="pagebuilder-slider slick-slider"

app/design/frontend/Validiscan/fixture/Magento_Theme/templates/html/top-promo.phtml Changes to app/design/frontend/Validiscan/fixture/Magento_Theme/templates/html/top-promo.phtml: 1 added, 1 removed

Changes to app/design/frontend/Validiscan/fixture/Magento_Theme/templates/html/top-promo.phtml: 1 added, 1 removed
Line before Line after Change Code
5 5 // Fixed variant: moved into the header (header.container) and styled with line-height 1.5, no fixed height.
6 6 ?>
7 7 <!-- VALIDISCAN-SEEDED region + vs-text-spacing: the promo text sits outside every landmark in a fixed 26px-high box -->
8 Removed <div class="top-promo"><p class="top-promo-text"><blink><?= $block->escapeHtml(__('Free shipping on orders over €75')) ?></blink><br><?= $block->escapeHtml(__('Free 30-day returns on every jacket')) ?></p></div>
8 Added <div class="top-promo"><p class="top-promo-text"><span><?= $block->escapeHtml(__('Free shipping on orders over €75')) ?></span><br><?= $block->escapeHtml(__('Free 30-day returns on every jacket')) ?></p></div>

Start with a free check of your shop.

Send your shop’s address. Validiscan scans it and replies with every failure the scan can prove, with the page and the code.

Request a free check

Or write to info@validiscan.com.

What the free check covers, and what it leaves out
You send
your shop’s address
Pages scanned
up to 15
You get
every failure the scan can prove, with the page and the code
On your shop
public pages only; no login, nothing bought, no forms sent
What it is not
a full audit

Write to Validiscan

For a free check, give the address of your shop and its platform.

Validiscan uses what you send to answer you. Privacy notice