<blink> elements are deprecated and must not be used
Blinking text is distracting and hard to read for customers with attention, reading or visual difficulties, and they have no way to stop it. Important content such as a sale message can be missed entirely.
- Rule id
- blink
- Source
- axe-core 4.13.0
- Impact
- Serious
- Fix tier
- AUTO
- on Shopify, Shopware, WooCommerce and Magento
- Status
- runs
What the check does
Ensure <blink> elements are not used
Selection is by tag name alone. The rule picks up each <blink> element in the document, whatever text or attributes it carries, and does not set hidden ones aside first. Each element then gets one test, axe-core’s is-on-screen check used in reverse: the element fails when it is visible on screen and passes when it is not.
Being out of sight means, for example, display: none or opacity: 0 on the element or an ancestor, visibility: hidden on the element itself, a zero-size clip or clip-path: circle(0), or a position entirely above the page. The test only answers yes or no, so the rule produces no needs-review results.
Validiscan’s scanner groups failures by a fingerprint that ignores generated ids and position indexes, so a <blink> in a header shared by all pages becomes one finding with a page count. Blinking made with CSS or a script is outside the selector. <marquee> has its own rule, and auto-advancing carousels are the subject of the vs-carousel check.
How to fix it
Remove every <blink> element and keep its text as normal content. If emphasis is needed, use static styling such as bold text or a badge; any animation must stop within five seconds or offer a pause control.
WCAG success criteria
- 2.2.2 Pause, Stop, Hide, level A
EN 301 549 clauses
| 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
Shopify: recipe remove-blink-marquee
Show the before and after (1)
sections/announcement-bar.liquid 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 |
Shopware: recipe remove-blink-marquee
Show the before and after (1)
Resources/views/storefront/layout/header/top-bar.html.twig 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> |
WooCommerce: recipe remove-blink-marquee
Show the before and after (2)
footer.php 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
| 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 |
functions.php 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
| 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> |
Magento: recipe remove-blink-marquee
Show the before and after (1)
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
| 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
| 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 checkOr 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