Auto-advancing carousels need a pause control and keyboard access
Moving banners pull attention away from what customers are trying to read, and people who read slowly, zoom in or have attention difficulties cannot finish a slide before it changes. Without keyboard-reachable arrows and named slides, keyboard and screen reader users cannot browse the offers at all.
- Rule id
- vs-carousel
- Source
- Validiscan check
- Impact
- Serious
- Fix tier
- AUTO
- on Shopify, Shopware, WooCommerce and Magento
- Status
- runs
What the check does
Detects hero sliders and product carousels that move on their own without a pause, stop or hide control (2.2.2), carousel controls that cannot be reached with the keyboard (2.1.1) and slides or controls without accessible names (4.1.2).
Slides are found by class names such as slide, carousel-item or swiper-slide, or by aria-roledescription="slide", clones excluded. Two or more sibling slides inside a visible carousel or slider container of at least 100 by 40 px make a carousel.
With the mouse and focus moved away, the check samples each carousel every 500 ms for up to 3.5 seconds: state classes, aria-hidden, opacity, transforms and scroll positions. Any change counts as auto-advance, as does autoplay declared in data-autoplay, data-ride or library options. One that first moves later and declares nothing is missed.
An auto-advancing carousel needs a pause control in the tab order, recognized by pause, stop or play wording in its class, id or name. Previous, next and dot controls must be in the tab order and named. Every slide is judged: one with role="group", role="tabpanel" or aria-roledescription needs a name, any other needs text or a text alternative.
The check never presses the pause control; a person confirms that it stops the rotation.
How to fix it
Add a visible pause/play button that stops the automatic rotation, pause it on hover and on focus, make the previous, next and pagination controls real buttons with labels such as "Next slide", and name each slide, for example "Slide 2 of 5". The common slider libraries (Slick, Swiper, Flickity, the Shopify Dawn slideshow) have options for all of this.
WCAG success criteria
- 2.2.2 Pause, Stop, Hide, level A
- 2.1.1 Keyboard, level A
- 4.1.2 Name, Role, Value, 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 |
| 2.1.1 | 9.2.1.1 | 9.2.1.1 |
| 4.1.2 | 9.4.1.2 | 9.4.1.2 |
Where a recipe fixes it
Shopify: recipe button-semantics
Show the before and after (1)
assets/base.css.liquid Changes to assets/base.css.liquid: 14 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1866 | 1866 | } | |
| 1867 | 1867 | ||
| 1868 | 1868 | /* ----------------------------------------------------------------- motion */ | |
| 1869 | Added | ||
| 1870 | Added | /* validiscan:button-semantics */ | |
| 1871 | Added | :where(button.slider-counter__link) { | |
| 1872 | Added | appearance: none; | |
| 1873 | Added | margin: 0; | |
| 1874 | Added | padding: 0; | |
| 1875 | Added | border: 0; | |
| 1876 | Added | background: none; | |
| 1877 | Added | color: inherit; | |
| 1878 | Added | font: inherit; | |
| 1879 | Added | text-align: inherit; | |
| 1880 | Added | cursor: pointer; | |
| 1881 | Added | } | |
| 1882 | Added | /* /validiscan:button-semantics */ |
sections/slideshow.liquid Changes to sections/slideshow.liquid: 1 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 62 | 62 | </button> | |
| 63 | 63 | <div class="slider-counter"> | |
| 64 | 64 | {%- for block in section.blocks %} | |
| 65 | Removed | <span class="slider-counter__link" data-slide-to="{{ forloop.index0 }}"><span class="dot"></span></span> | |
| 65 | Added | <button class="slider-counter__link" data-slide-to="{{ forloop.index0 }}" type="button"><span class="dot"></span><span class="visually-hidden">{{ 'accessibility.load_slide' | t: index: forloop.index, count: forloop.length }}</span></button> | |
| 66 | 66 | {%- endfor %} | |
| 67 | 67 | </div> | |
| 68 | 68 | <button type="button" class="slider-button slider-button--next" name="next" data-slide-next> |
Shopify: recipe icon-accessible-name
Show the before and after (2)
locales/en.default.json Changes to locales/en.default.json: 3 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 34 | 34 | "total_reviews": "{{ count }} reviews", | |
| 35 | 35 | "link_messages": { | |
| 36 | 36 | "new_window": "Opens in a new window." | |
| 37 | Removed | } | |
| 37 | Added | }, | |
| 38 | Added | "accept_cookies": "Accept cookies", | |
| 39 | Added | "reject_cookies": "Reject cookies" | |
| 38 | 40 | }, | |
| 39 | 41 | "sections": { | |
| 40 | 42 | "header": { |
sections/header.liquid Changes to sections/header.liquid: 1 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 40 | 40 | <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}" tabindex="1"> | |
| 41 | 41 | <button type="submit" class="search__button"> | |
| 42 | 42 | {%- render 'icon', icon: 'search', size: 20 -%} | |
| 43 | Added | <span class="visually-hidden">{{ 'general.search.search' | t }}</span> | |
| 43 | 44 | </button> | |
| 44 | 45 | </form> | |
| 45 | 46 | </div> |
sections/main-product.liquid Changes to sections/main-product.liquid: 1 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 88 | 88 | <p class="form__label">{{ option.name | escape }}</p> | |
| 89 | 89 | <div class="swatch-list swatch-list--compact"> | |
| 90 | 90 | {%- for swatch in option.swatches %} | |
| 91 | Removed | <button type="button" class="swatch swatch--button{% if swatch.selected %} swatch--active{% endif %}" style="--swatch-color: {{ swatch.color }};" data-option-index="{{ option_index }}" data-value="{{ swatch.value | escape }}"></button> | |
| 91 | Added | <button type="button" class="swatch swatch--button{% if swatch.selected %} swatch--active{% endif %}" style="--swatch-color: {{ swatch.color }};" data-option-index="{{ option_index }}" data-value="{{ swatch.value | escape }}"><span class="visually-hidden">{{ swatch.value | escape }}</span></button> | |
| 92 | 92 | {%- endfor %} | |
| 93 | 93 | </div> | |
| 94 | 94 | </div> |
sections/slideshow.liquid Changes to sections/slideshow.liquid: 2 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 59 | 59 | <div class="slideshow__controls"> | |
| 60 | 60 | <button type="button" class="slider-button slider-button--prev" name="previous" data-slide-prev> | |
| 61 | 61 | {%- render 'icon', icon: 'chevron-left', size: 20 -%} | |
| 62 | Added | <span class="visually-hidden">{{ 'accessibility.previous_slide' | t }}</span> | |
| 62 | 63 | </button> | |
| 63 | 64 | <div class="slider-counter"> | |
| 64 | 65 | {%- for block in section.blocks %} | |
| 67 | 68 | </div> | |
| 68 | 69 | <button type="button" class="slider-button slider-button--next" name="next" data-slide-next> | |
| 69 | 70 | {%- render 'icon', icon: 'chevron-right', size: 20 -%} | |
| 71 | Added | <span class="visually-hidden">{{ 'accessibility.next_slide' | t }}</span> | |
| 70 | 72 | </button> | |
| 71 | 73 | </div> | |
| 72 | 74 | </slideshow-component> |
snippets/cookie-banner.liquid Changes to snippets/cookie-banner.liquid: 2 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 23 | 23 | <div class="cookie-banner__actions"> | |
| 24 | 24 | <button type="button" class="cookie-banner__icon-button cookie-banner__icon-button--accept" data-cookie-accept> | |
| 25 | 25 | {%- render 'icon', icon: 'check', size: 20 -%} | |
| 26 | Added | <span class="visually-hidden">{{ 'accessibility.accept_cookies' | t }}</span> | |
| 26 | 27 | </button> | |
| 27 | 28 | <button type="button" class="cookie-banner__icon-button" data-cookie-reject> | |
| 28 | 29 | {%- render 'icon', icon: 'close', size: 20 -%} | |
| 30 | Added | <span class="visually-hidden">{{ 'accessibility.reject_cookies' | t }}</span> | |
| 29 | 31 | </button> | |
| 30 | 32 | </div> | |
| 31 | 33 | </div> |
snippets/quantity-input.liquid Changes to snippets/quantity-input.liquid: 2 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 9 | 9 | {%- endcomment -%} | |
| 10 | 10 | <div class="quantity quantity--compact" data-quantity{% if line %} data-line="{{ line }}"{% endif %}><button class="quantity__button" name="minus" type="button" data-quantity-minus> | |
| 11 | 11 | {%- render 'icon', icon: 'minus', size: 12 -%} | |
| 12 | Added | <span class="visually-hidden">{{ 'products.product.quantity.decrease' | t: product: product_title }}</span> | |
| 12 | 13 | </button> | |
| 13 | 14 | <input class="quantity__input" type="number" name="{{ input_name }}" id="{{ input_id }}" value="{{ value | default: 1 }}" min="{% if line %}0{% else %}1{% endif %}" data-quantity-input> | |
| 14 | 15 | <button class="quantity__button" name="plus" type="button" data-quantity-plus> | |
| 15 | 16 | {%- render 'icon', icon: 'plus', size: 12 -%} | |
| 17 | Added | <span class="visually-hidden">{{ 'products.product.quantity.increase' | t: product: product_title }}</span> | |
| 16 | 18 | </button></div> |
sections/footer.liquid Changes to sections/footer.liquid: 1 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 37 | 37 | {%- for social in shop.social %} | |
| 38 | 38 | <a href="{{ social.url }}" class="list-social__link link"> | |
| 39 | 39 | {%- render 'icon', icon: social.icon, size: 20 -%} | |
| 40 | Added | <span class="visually-hidden">{{ 'general.social.links.' | append: social.icon | t }}</span> | |
| 40 | 41 | </a> | |
| 41 | 42 | {%- endfor %} | |
| 42 | 43 | </ul> |
sections/header.liquid Changes to sections/header.liquid: 3 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 22 | 22 | </details> | |
| 23 | 23 | ||
| 24 | 24 | {% if logo_is_heading %}<h1 class="header__heading">{% else %}<div class="header__heading">{% endif %} | |
| 25 | Removed | <a href="{{ routes.root_url }}" class="header__heading-link"><img src="{{ 'logo.svg' | asset_url }}" width="{{ settings.logo_width }}" height="32" class="header__heading-logo"></a> | |
| 25 | Added | <a href="{{ routes.root_url }}" class="header__heading-link"><img src="{{ 'logo.svg' | asset_url }}" width="{{ settings.logo_width }}" height="32" class="header__heading-logo" alt="{{ shop.name | escape }}"></a> | |
| 26 | 26 | {% if logo_is_heading %}</h1>{% else %}</div>{% endif %} | |
| 27 | 27 | ||
| 28 | 28 | <nav class="header__inline-menu"> | |
| 50 | 50 | {%- endif %} | |
| 51 | 51 | <a href="{{ routes.account_login_url }}" class="header__icon header__icon--account link"> | |
| 52 | 52 | {%- render 'icon', icon: 'account', size: icon_size -%} | |
| 53 | Added | <span class="visually-hidden">{{ 'sections.header.account' | t }}</span> | |
| 53 | 54 | </a> | |
| 54 | 55 | <a href="{{ routes.cart_url }}" class="header__icon header__icon--cart link" id="cart-icon-bubble"> | |
| 55 | 56 | {%- render 'icon', icon: 'cart', size: icon_size -%} | |
| 57 | 58 | <span class="cart-count-bubble" aria-hidden="true"><span data-cart-count>{{ cart.item_count }}</span></span> | |
| 58 | 59 | {%- endif -%} | |
| 59 | 60 | ||
| 61 | Added | <span class="visually-hidden">{{ 'sections.header.cart' | t }}</span> | |
| 60 | 62 | </a> | |
| 61 | 63 | </div> | |
| 62 | 64 | </header> |
sections/main-cart.liquid Changes to sections/main-cart.liquid: 1 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 26 | 26 | {% render 'quantity-input', input_id: qty_id, input_name: 'updates[]', value: item.quantity, product_title: item.product.title, line: line %} | |
| 27 | 27 | <a href="{{ routes.cart_change_url }}?line={{ line }}&quantity=0" class="cart-item__remove cart-item__remove--compact" data-cart-remove> | |
| 28 | 28 | {%- render 'icon', icon: 'trash', size: 16 -%} | |
| 29 | Added | <span class="visually-hidden">{{ 'sections.cart.remove' | t: title: item.product.title }}</span> | |
| 29 | 30 | </a> | |
| 30 | 31 | </div> | |
| 31 | 32 | <div class="cart-item__totals"> |
Shopify: recipe slider-pause-control
Show the before and after (1)
assets/base.css.liquid Changes to assets/base.css.liquid: 21 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1866 | 1866 | } | |
| 1867 | 1867 | ||
| 1868 | 1868 | /* ----------------------------------------------------------------- motion */ | |
| 1869 | Added | ||
| 1870 | Added | /* validiscan:slider-pause-control */ | |
| 1871 | Added | [data-autoplay-paused], | |
| 1872 | Added | [data-autoplay-paused] * { | |
| 1873 | Added | animation-play-state: paused !important; | |
| 1874 | Added | } | |
| 1875 | Added | ||
| 1876 | Added | .slider-pause { | |
| 1877 | Added | display: inline-flex; | |
| 1878 | Added | align-items: center; | |
| 1879 | Added | justify-content: center; | |
| 1880 | Added | min-width: 2.75rem; | |
| 1881 | Added | min-height: 2.75rem; | |
| 1882 | Added | padding: 0.5rem 1rem; | |
| 1883 | Added | border: 1px solid currentColor; | |
| 1884 | Added | background: transparent; | |
| 1885 | Added | color: inherit; | |
| 1886 | Added | font: inherit; | |
| 1887 | Added | cursor: pointer; | |
| 1888 | Added | } | |
| 1889 | Added | /* /validiscan:slider-pause-control */ |
assets/global.js Changes to assets/global.js: 53 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 412 | 412 | if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); | |
| 413 | 413 | else boot(); | |
| 414 | 414 | })(); | |
| 415 | Added | ||
| 416 | Added | /* validiscan:slider-pause-control */ | |
| 417 | Added | (function () { | |
| 418 | Added | 'use strict'; | |
| 419 | Added | var ROOTS = 'slideshow-component, slider-component, .swiper, .swiper-container, .slick-slider, .flickity-enabled, .splide, [data-autoplay]'; | |
| 420 | Added | var reduce = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)') : null; | |
| 421 | Added | ||
| 422 | Added | function rootOf(button) { | |
| 423 | Added | return button.closest(ROOTS) || button.previousElementSibling; | |
| 424 | Added | } | |
| 425 | Added | ||
| 426 | Added | function setPaused(button, paused) { | |
| 427 | Added | var root = rootOf(button); | |
| 428 | Added | if (!root) return; | |
| 429 | Added | if (paused) root.setAttribute('data-autoplay-paused', ''); | |
| 430 | Added | else root.removeAttribute('data-autoplay-paused'); | |
| 431 | Added | if (root.swiper && root.swiper.autoplay) { | |
| 432 | Added | if (paused) root.swiper.autoplay.stop(); | |
| 433 | Added | else root.swiper.autoplay.start(); | |
| 434 | Added | } | |
| 435 | Added | var $ = window.jQuery; | |
| 436 | Added | if ($ && $(root).hasClass('slick-initialized')) $(root).slick(paused ? 'slickPause' : 'slickPlay'); | |
| 437 | Added | var flickity = window.Flickity && window.Flickity.data(root); | |
| 438 | Added | if (flickity) { | |
| 439 | Added | if (paused) flickity.pausePlayer(); | |
| 440 | Added | else flickity.unpausePlayer(); | |
| 441 | Added | } | |
| 442 | Added | var autoplay = root.splide && root.splide.Components && root.splide.Components.Autoplay; | |
| 443 | Added | if (autoplay) { | |
| 444 | Added | if (paused) autoplay.pause(); | |
| 445 | Added | else autoplay.play(); | |
| 446 | Added | } | |
| 447 | Added | if (root.localName.indexOf('-') > 0 && typeof root.pause === 'function' && typeof root.play === 'function') { | |
| 448 | Added | if (paused) root.pause(); | |
| 449 | Added | else root.play(); | |
| 450 | Added | } | |
| 451 | Added | button.setAttribute('data-paused', paused ? 'true' : 'false'); | |
| 452 | Added | button.textContent = button.getAttribute(paused ? 'data-label-play' : 'data-label-pause') || button.textContent; | |
| 453 | Added | } | |
| 454 | Added | ||
| 455 | Added | function init() { | |
| 456 | Added | Array.prototype.forEach.call(document.querySelectorAll('[data-slider-pause]'), function (button) { | |
| 457 | Added | button.addEventListener('click', function () { | |
| 458 | Added | setPaused(button, button.getAttribute('data-paused') !== 'true'); | |
| 459 | Added | }); | |
| 460 | Added | if (reduce && reduce.matches) setPaused(button, true); | |
| 461 | Added | }); | |
| 462 | Added | } | |
| 463 | Added | ||
| 464 | Added | if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); | |
| 465 | Added | else init(); | |
| 466 | Added | })(); | |
| 467 | Added | /* /validiscan:slider-pause-control */ |
locales/en.default.json Changes to locales/en.default.json: 3 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 34 | 34 | "total_reviews": "{{ count }} reviews", | |
| 35 | 35 | "link_messages": { | |
| 36 | 36 | "new_window": "Opens in a new window." | |
| 37 | Removed | } | |
| 37 | Added | }, | |
| 38 | Added | "pause_slideshow": "Pause slideshow", | |
| 39 | Added | "play_slideshow": "Play slideshow" | |
| 38 | 40 | }, | |
| 39 | 41 | "sections": { | |
| 40 | 42 | "header": { |
sections/slideshow.liquid Changes to sections/slideshow.liquid: 3 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 68 | 68 | <button type="button" class="slider-button slider-button--next" name="next" data-slide-next> | |
| 69 | 69 | {%- render 'icon', icon: 'chevron-right', size: 20 -%} | |
| 70 | 70 | </button> | |
| 71 | Added | {%- if autoplay %} | |
| 72 | Added | <button type="button" class="slider-pause" data-slider-pause data-label-pause="{{ 'accessibility.pause_slideshow' | t | escape }}" data-label-play="{{ 'accessibility.play_slideshow' | t | escape }}">{{ 'accessibility.pause_slideshow' | t }}</button> | |
| 73 | Added | {%- endif %} | |
| 71 | 74 | </div> | |
| 72 | 75 | </slideshow-component> | |
| 73 | 76 |
Shopware: recipe button-semantics
Show the before and after (1)
Resources/app/storefront/src/scss/base.scss Changes to Resources/app/storefront/src/scss/base.scss: 17 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1708 | 1708 | margin: 8px 0 0; | |
| 1709 | 1709 | font-size: 0.875rem; | |
| 1710 | 1710 | } | |
| 1711 | Added | ||
| 1712 | Added | /* validiscan:button-semantics */ | |
| 1713 | Added | /* Former <div>/<span>/<li> controls, now <button>: drop the browser button styles, keep the theme's (no specificity). */ | |
| 1714 | Added | :where(button.base-slider-dot) { | |
| 1715 | Added | display: block; | |
| 1716 | Added | margin: 0; | |
| 1717 | Added | padding: 0; | |
| 1718 | Added | border: 0; | |
| 1719 | Added | background: none; | |
| 1720 | Added | color: inherit; | |
| 1721 | Added | font: inherit; | |
| 1722 | Added | line-height: inherit; | |
| 1723 | Added | text-align: inherit; | |
| 1724 | Added | cursor: pointer; | |
| 1725 | Added | appearance: none; | |
| 1726 | Added | } | |
| 1727 | Added | /* /validiscan:button-semantics */ |
Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 5 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", | |
| 194 | 194 | "backToHome": "Zurück zur Startseite", | |
| 195 | 195 | "searchInstead": "Unsere Kaffees durchsuchen" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "control": { | |
| 199 | Added | "showSlide": "Folie %index% anzeigen" | |
| 200 | Added | } | |
| 196 | 201 | } | |
| 197 | 202 | } |
Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 5 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "The page you are looking for does not exist or has moved.", | |
| 194 | 194 | "backToHome": "Back to the homepage", | |
| 195 | 195 | "searchInstead": "Search our coffees" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "control": { | |
| 199 | Added | "showSlide": "Show slide %index%" | |
| 200 | Added | } | |
| 196 | 201 | } | |
| 197 | 202 | } |
Resources/views/storefront/element/cms-element-image-slider.html.twig Changes to Resources/views/storefront/element/cms-element-image-slider.html.twig: 1 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 51 | 51 | </button> | |
| 52 | 52 | <ol class="base-slider-dots"> | |
| 53 | 53 | {% for slide in slides %} | |
| 54 | Removed | <li class="base-slider-dot{% if loop.first %} is-active{% endif %}" data-slide-to="{{ loop.index0 }}"></li> | |
| 54 | Added | <li><button class="base-slider-dot{% if loop.first %} is-active{% endif %}" data-slide-to="{{ loop.index0 }}" type="button" aria-label="{{ 'a11y.control.showSlide'|trans({'%index%': loop.index})|striptags }}"></button></li> | |
| 55 | 55 | {% endfor %} | |
| 56 | 56 | </ol> | |
| 57 | 57 | <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next> |
Shopware: recipe icon-accessible-name
Show the before and after (2)
Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 12 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", | |
| 194 | 194 | "backToHome": "Zurück zur Startseite", | |
| 195 | 195 | "searchInstead": "Unsere Kaffees durchsuchen" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "control": { | |
| 199 | Added | "search": "Suchen", | |
| 200 | Added | "previousSlide": "Vorherige Folie", | |
| 201 | Added | "nextSlide": "Nächste Folie", | |
| 202 | Added | "cookieSettings": "Cookie-Einstellungen", | |
| 203 | Added | "acceptCookies": "Alle Cookies akzeptieren", | |
| 204 | Added | "decreaseQuantity": "Menge verringern", | |
| 205 | Added | "increaseQuantity": "Menge erhöhen", | |
| 206 | Added | "removeFromCart": "Aus dem Warenkorb entfernen" | |
| 207 | Added | } | |
| 196 | 208 | } | |
| 197 | 209 | } |
Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 12 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "The page you are looking for does not exist or has moved.", | |
| 194 | 194 | "backToHome": "Back to the homepage", | |
| 195 | 195 | "searchInstead": "Search our coffees" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "control": { | |
| 199 | Added | "search": "Search", | |
| 200 | Added | "previousSlide": "Previous slide", | |
| 201 | Added | "nextSlide": "Next slide", | |
| 202 | Added | "cookieSettings": "Cookie settings", | |
| 203 | Added | "acceptCookies": "Accept all cookies", | |
| 204 | Added | "decreaseQuantity": "Decrease quantity", | |
| 205 | Added | "increaseQuantity": "Increase quantity", | |
| 206 | Added | "removeFromCart": "Remove from cart" | |
| 207 | Added | } | |
| 196 | 208 | } | |
| 197 | 209 | } |
Resources/views/storefront/element/cms-element-image-gallery.html.twig Changes to Resources/views/storefront/element/cms-element-image-gallery.html.twig: 2 added, 2 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 31 | 31 | ||
| 32 | 32 | {% if media|length > 1 %} | |
| 33 | 33 | <div class="gallery-slider-controls"> | |
| 34 | Removed | <button type="button" class="base-slider-controls-prev gallery-slider-controls-prev" data-gallery-prev> | |
| 34 | Added | <button type="button" class="base-slider-controls-prev gallery-slider-controls-prev" data-gallery-prev aria-label="{{ 'a11y.control.previousSlide'|trans|striptags }}"> | |
| 35 | 35 | {% sw_icon 'arrow-head-left' %} | |
| 36 | 36 | </button> | |
| 37 | Removed | <button type="button" class="base-slider-controls-next gallery-slider-controls-next" data-gallery-next> | |
| 37 | Added | <button type="button" class="base-slider-controls-next gallery-slider-controls-next" data-gallery-next aria-label="{{ 'a11y.control.nextSlide'|trans|striptags }}"> | |
| 38 | 38 | {% sw_icon 'arrow-head-right' %} | |
| 39 | 39 | </button> | |
| 40 | 40 | </div> |
Resources/views/storefront/element/cms-element-image-slider.html.twig Changes to Resources/views/storefront/element/cms-element-image-slider.html.twig: 2 added, 2 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 46 | 46 | ||
| 47 | 47 | {% block element_image_slider_controls %} | |
| 48 | 48 | <div class="image-slider-controls-container"> | |
| 49 | Removed | <button type="button" class="base-slider-controls-prev image-slider-controls-btn" data-slide-prev> | |
| 49 | Added | <button type="button" class="base-slider-controls-prev image-slider-controls-btn" data-slide-prev aria-label="{{ 'a11y.control.previousSlide'|trans|striptags }}"> | |
| 50 | 50 | {% sw_icon 'arrow-head-left' %} | |
| 51 | 51 | </button> | |
| 52 | 52 | <ol class="base-slider-dots"> | |
| 54 | 54 | <li class="base-slider-dot{% if loop.first %} is-active{% endif %}" data-slide-to="{{ loop.index0 }}"></li> | |
| 55 | 55 | {% endfor %} | |
| 56 | 56 | </ol> | |
| 57 | Removed | <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next> | |
| 57 | Added | <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next aria-label="{{ 'a11y.control.nextSlide'|trans|striptags }}"> | |
| 58 | 58 | {% sw_icon 'arrow-head-right' %} | |
| 59 | 59 | </button> | |
| 60 | 60 | </div> |
Resources/views/storefront/layout/cookie/cookie-permission.html.twig Changes to Resources/views/storefront/layout/cookie/cookie-permission.html.twig: 2 added, 2 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 22 | 22 | </p> | |
| 23 | 23 | </div> | |
| 24 | 24 | <div class="col-auto cookie-permission-actions"> | |
| 25 | Removed | <button type="button" class="btn cookie-permission-icon-btn js-cookie-configuration-toggle">{% sw_icon 'settings' %}</button> | |
| 26 | Removed | <button type="button" class="btn btn-primary cookie-permission-icon-btn js-cookie-accept-all-button">{% sw_icon 'checkmark' %}</button> | |
| 25 | Added | <button type="button" class="btn cookie-permission-icon-btn js-cookie-configuration-toggle" aria-label="{{ 'a11y.control.cookieSettings'|trans|striptags }}">{% sw_icon 'settings' %}</button> | |
| 26 | Added | <button type="button" class="btn btn-primary cookie-permission-icon-btn js-cookie-accept-all-button" aria-label="{{ 'a11y.control.acceptCookies'|trans|striptags }}">{% sw_icon 'checkmark' %}</button> | |
| 27 | 27 | </div> | |
| 28 | 28 | </div> | |
| 29 | 29 | <p class="cookie-permission-configuration" hidden>{{ 'cookie.configurationText'|trans }}</p> |
Resources/views/storefront/layout/header/search.html.twig Changes to Resources/views/storefront/layout/header/search.html.twig: 1 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 13 | 13 | autocomplete="off" | |
| 14 | 14 | autocapitalize="off" | |
| 15 | 15 | placeholder="{{ 'header.searchPlaceholder'|trans }}" value="{{ page.searchTerm }}"> | |
| 16 | Removed | <button type="submit" class="btn header-search-btn"> | |
| 16 | Added | <button type="submit" class="btn header-search-btn" aria-label="{{ 'a11y.control.search'|trans|striptags }}"> | |
| 17 | 17 | <span class="header-search-icon">{% sw_icon 'search' %}</span> | |
| 18 | 18 | </button> | |
| 19 | 19 | </div> |
Resources/views/storefront/page/checkout/cart/index.html.twig Changes to Resources/views/storefront/page/checkout/cart/index.html.twig: 3 added, 3 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 39 | 39 | </div> | |
| 40 | 40 | <div class="line-item-quantity"> | |
| 41 | 41 | <div class="input-group quantity-selector-group" data-quantity-selector="true"> | |
| 42 | Removed | <button type="button" class="btn btn-outline-light btn-minus js-btn-minus"> | |
| 42 | Added | <button type="button" class="btn btn-outline-light btn-minus js-btn-minus" aria-label="{{ 'a11y.control.decreaseQuantity'|trans|striptags }}"> | |
| 43 | 43 | {% sw_icon 'minus' style { size: 'xs' } %} | |
| 44 | 44 | </button> | |
| 45 | 45 | <input type="number" | |
| 50 | 50 | max="100" | |
| 51 | 51 | step="1" | |
| 52 | 52 | value="{{ item.quantity }}"> | |
| 53 | Removed | <button type="button" class="btn btn-outline-light btn-plus js-btn-plus"> | |
| 53 | Added | <button type="button" class="btn btn-outline-light btn-plus js-btn-plus" aria-label="{{ 'a11y.control.increaseQuantity'|trans|striptags }}"> | |
| 54 | 54 | {% sw_icon 'plus' style { size: 'xs' } %} | |
| 55 | 55 | </button> | |
| 56 | 56 | </div> | |
| 64 | 64 | <span class="line-item-total-price-value" data-line-total>{{ item.totalPrice|currency }}*</span> | |
| 65 | 65 | </div> | |
| 66 | 66 | <div class="line-item-remove"> | |
| 67 | Removed | <button type="button" class="btn btn-light btn-sm line-item-remove-button"> | |
| 67 | Added | <button type="button" class="btn btn-light btn-sm line-item-remove-button" aria-label="{{ 'a11y.control.removeFromCart'|trans|striptags }}"> | |
| 68 | 68 | {% sw_icon 'x' style { size: 'xs' } %} | |
| 69 | 69 | </button> | |
| 70 | 70 | </div> |
Resources/views/storefront/page/product-detail/buy-widget.html.twig Changes to Resources/views/storefront/page/product-detail/buy-widget.html.twig: 2 added, 2 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 64 | 64 | <div class="buy-widget-container"> | |
| 65 | 65 | <div class="buy-widget-quantity"> | |
| 66 | 66 | <div class="input-group quantity-selector-group" data-quantity-selector="true"> | |
| 67 | Removed | <button type="button" class="btn btn-outline-light btn-minus js-btn-minus"> | |
| 67 | Added | <button type="button" class="btn btn-outline-light btn-minus js-btn-minus" aria-label="{{ 'a11y.control.decreaseQuantity'|trans|striptags }}"> | |
| 68 | 68 | {% sw_icon 'minus' style { size: 'xs' } %} | |
| 69 | 69 | </button> | |
| 70 | 70 | <input type="number" | |
| 75 | 75 | max="100" | |
| 76 | 76 | step="1" | |
| 77 | 77 | value="1"> | |
| 78 | Removed | <button type="button" class="btn btn-outline-light btn-plus js-btn-plus"> | |
| 78 | Added | <button type="button" class="btn btn-outline-light btn-plus js-btn-plus" aria-label="{{ 'a11y.control.increaseQuantity'|trans|striptags }}"> | |
| 79 | 79 | {% sw_icon 'plus' style { size: 'xs' } %} | |
| 80 | 80 | </button> | |
| 81 | 81 | </div> |
Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 6 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", | |
| 194 | 194 | "backToHome": "Zurück zur Startseite", | |
| 195 | 195 | "searchInstead": "Unsere Kaffees durchsuchen" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "control": { | |
| 199 | Added | "home": "Zur Startseite", | |
| 200 | Added | "account": "Ihr Konto" | |
| 201 | Added | } | |
| 196 | 202 | } | |
| 197 | 203 | } |
Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 6 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "The page you are looking for does not exist or has moved.", | |
| 194 | 194 | "backToHome": "Back to the homepage", | |
| 195 | 195 | "searchInstead": "Search our coffees" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "control": { | |
| 199 | Added | "home": "Go to the homepage", | |
| 200 | Added | "account": "Your account" | |
| 201 | Added | } | |
| 196 | 202 | } | |
| 197 | 203 | } |
Resources/views/storefront/layout/header/actions.html.twig Changes to Resources/views/storefront/layout/header/actions.html.twig: 2 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 3 | 3 | {% block layout_header_actions_account %} | |
| 4 | 4 | <div class="header-account"> | |
| 5 | 5 | <a href="{{ url('/account/login') }}" | |
| 6 | Removed | class="btn account-menu-btn header-actions-btn"> | |
| 6 | Added | class="btn account-menu-btn header-actions-btn" | |
| 7 | Added | aria-label="{{ 'a11y.control.account'|trans|striptags }}"> | |
| 7 | 8 | {% sw_icon 'avatar' %} | |
| 8 | 9 | </a> | |
| 9 | 10 | </div> |
Resources/views/storefront/layout/header/logo.html.twig Changes to Resources/views/storefront/layout/header/logo.html.twig: 1 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 2 | 2 | <div class="header-logo-main"> | |
| 3 | 3 | {% block layout_header_logo_link %} | |
| 4 | 4 | {# The agency removed the default title="Go to homepage" and the image alt to "avoid duplicate announcements". #} | |
| 5 | Removed | <a class="header-logo-main-link" href="{{ url('/') }}"> | |
| 5 | Added | <a class="header-logo-main-link" href="{{ url('/') }}" aria-label="{{ 'a11y.control.home'|trans|striptags }}"> | |
| 6 | 6 | {% block layout_header_logo_image %} | |
| 7 | 7 | <picture class="header-logo-picture"> | |
| 8 | 8 | <img src="{{ asset('bundles/storefront/assets/logo/kaffeekontor-nord-logo.svg') }}" |
Shopware: recipe slider-pause-control
Show the before and after (1)
Resources/app/storefront/src/main.js Changes to Resources/app/storefront/src/main.js: 52 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 142 | 142 | if (options.autoplay === true) { | |
| 143 | 143 | window.setInterval( | |
| 144 | 144 | function () { | |
| 145 | Added | if (slider.getAttribute('data-autoplay-paused') === 'true') return; | |
| 145 | 146 | show(current + 1); | |
| 146 | 147 | }, | |
| 147 | 148 | Number(options.autoplayTimeout) || 5000, | |
| 453 | 454 | initFilterRanges(); | |
| 454 | 455 | initToggles(); | |
| 455 | 456 | })(); | |
| 457 | Added | ||
| 458 | Added | /* validiscan:slider-pause-control */ | |
| 459 | Added | /* | |
| 460 | Added | * Pause / play button of auto-advancing sliders (WCAG 2.2.2): wired to the | |
| 461 | Added | * slider's autoplay; sliders start paused when the visitor prefers reduced motion. | |
| 462 | Added | */ | |
| 463 | Added | (function sliderPauseControl() { | |
| 464 | Added | 'use strict'; | |
| 465 | Added | ||
| 466 | Added | function tinySlider(slider) { | |
| 467 | Added | const manager = window.PluginManager; | |
| 468 | Added | if (!manager || typeof manager.getPluginInstanceFromElement !== 'function') return null; | |
| 469 | Added | const plugin = manager.getPluginInstanceFromElement(slider, 'BaseSlider'); | |
| 470 | Added | return plugin && plugin._slider ? plugin._slider : null; | |
| 471 | Added | } | |
| 472 | Added | ||
| 473 | Added | function autoplays(slider) { | |
| 474 | Added | try { | |
| 475 | Added | const options = JSON.parse(slider.getAttribute('data-base-slider-options') || '{}') || {}; | |
| 476 | Added | return Boolean(options.slider && options.slider.autoplay); | |
| 477 | Added | } catch { | |
| 478 | Added | return false; | |
| 479 | Added | } | |
| 480 | Added | } | |
| 481 | Added | ||
| 482 | Added | function init() { | |
| 483 | Added | const reduceMotion = | |
| 484 | Added | window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; | |
| 485 | Added | document.querySelectorAll('[data-slider-pause]').forEach(function (button) { | |
| 486 | Added | const slider = button.closest('[data-base-slider]'); | |
| 487 | Added | if (!slider || !autoplays(slider)) return; | |
| 488 | Added | ||
| 489 | Added | function setPaused(paused) { | |
| 490 | Added | slider.setAttribute('data-autoplay-paused', paused ? 'true' : 'false'); | |
| 491 | Added | button.textContent = button.getAttribute(paused ? 'data-label-play' : 'data-label-pause'); | |
| 492 | Added | const instance = tinySlider(slider); | |
| 493 | Added | if (instance) instance[paused ? 'pause' : 'play'](); | |
| 494 | Added | } | |
| 495 | Added | ||
| 496 | Added | button.hidden = false; | |
| 497 | Added | button.addEventListener('click', function () { | |
| 498 | Added | setPaused(slider.getAttribute('data-autoplay-paused') !== 'true'); | |
| 499 | Added | }); | |
| 500 | Added | if (reduceMotion) setPaused(true); | |
| 501 | Added | }); | |
| 502 | Added | } | |
| 503 | Added | ||
| 504 | Added | if (document.readyState === 'complete') init(); | |
| 505 | Added | else window.addEventListener('load', init); | |
| 506 | Added | })(); | |
| 507 | Added | /* /validiscan:slider-pause-control */ |
Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Changes to Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json: 6 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", | |
| 194 | 194 | "backToHome": "Zurück zur Startseite", | |
| 195 | 195 | "searchInstead": "Unsere Kaffees durchsuchen" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "slider": { | |
| 199 | Added | "pause": "Diashow anhalten", | |
| 200 | Added | "play": "Diashow abspielen" | |
| 201 | Added | } | |
| 196 | 202 | } | |
| 197 | 203 | } |
Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Changes to Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json: 6 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 193 | 193 | "notFoundText": "The page you are looking for does not exist or has moved.", | |
| 194 | 194 | "backToHome": "Back to the homepage", | |
| 195 | 195 | "searchInstead": "Search our coffees" | |
| 196 | Added | }, | |
| 197 | Added | "a11y": { | |
| 198 | Added | "slider": { | |
| 199 | Added | "pause": "Pause slideshow", | |
| 200 | Added | "play": "Play slideshow" | |
| 201 | Added | } | |
| 196 | 202 | } | |
| 197 | 203 | } |
Resources/views/storefront/element/cms-element-image-slider.html.twig Changes to Resources/views/storefront/element/cms-element-image-slider.html.twig: 1 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 57 | 57 | <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next> | |
| 58 | 58 | {% sw_icon 'arrow-head-right' %} | |
| 59 | 59 | </button> | |
| 60 | Added | <button type="button" class="btn btn-light base-slider-pause" data-slider-pause="true" data-label-pause="{{ 'a11y.slider.pause'|trans|striptags }}" data-label-play="{{ 'a11y.slider.play'|trans|striptags }}" hidden>{{ 'a11y.slider.pause'|trans|sw_sanitize }}</button> | |
| 60 | 61 | </div> | |
| 61 | 62 | {% endblock %} | |
| 62 | 63 | </div> |
WooCommerce: recipe button-semantics
Show the before and after (1)
assets/css/main.css Changes to assets/css/main.css: 17 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 766 | 766 | gap: 0.75rem; | |
| 767 | 767 | } | |
| 768 | 768 | ||
| 769 | Added | /* validiscan:button-semantics */ | |
| 770 | Added | /* Controls that became <button>s: keep the look of the elements they replace. The theme | |
| 771 | Added | rules for these classes follow and still win. */ | |
| 769 | 772 | .kb-cookie-bar__settings, | |
| 770 | 773 | .kb-cookie-bar__accept { | |
| 774 | Added | margin: 0; | |
| 775 | Added | padding: 0; | |
| 776 | Added | border: 0; | |
| 777 | Added | background: none; | |
| 778 | Added | color: inherit; | |
| 779 | Added | font: inherit; | |
| 780 | Added | line-height: inherit; | |
| 781 | Added | text-align: inherit; | |
| 782 | Added | cursor: pointer; | |
| 783 | Added | } | |
| 784 | Added | /* /validiscan:button-semantics */ | |
| 785 | Added | ||
| 786 | Added | .kb-cookie-bar__settings, | |
| 787 | Added | .kb-cookie-bar__accept { | |
| 771 | 788 | padding: 0.6em 1.1em; | |
| 772 | 789 | border-radius: 4px; | |
| 773 | 790 | font-size: 0.9rem; |
template-parts/cookie-bar.php Changes to template-parts/cookie-bar.php: 3 added, 3 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 21 | 21 | <a href="<?php echo esc_url( get_privacy_policy_url() ); ?>"><?php esc_html_e( 'Privacy policy', 'kestrel-birch' ); ?></a> | |
| 22 | 22 | </p> | |
| 23 | 23 | <div class="kb-cookie-bar__actions"> | |
| 24 | Removed | <span class="kb-cookie-bar__settings" data-kb-consent="settings"><?php esc_html_e( 'Cookie settings', 'kestrel-birch' ); ?></span> | |
| 25 | Removed | <span class="kb-cookie-bar__accept" data-kb-consent="accept"><?php esc_html_e( 'Accept', 'kestrel-birch' ); ?></span> | |
| 26 | Removed | <button type="button" class="kb-cookie-bar__close" data-kb-consent="close"><?php kb_icon( 'close' ); ?></button> | |
| 24 | Added | <button class="kb-cookie-bar__settings" data-kb-consent="settings" type="button"><?php esc_html_e( 'Cookie settings', 'kestrel-birch' ); ?></button> | |
| 25 | Added | <button class="kb-cookie-bar__accept" data-kb-consent="accept" type="button"><?php esc_html_e( 'Accept', 'kestrel-birch' ); ?></button> | |
| 26 | Added | <button type="button" class="kb-cookie-bar__close" data-kb-consent="close"><?php kb_icon( 'close' ); ?><span class="screen-reader-text"><?php esc_html_e( 'Close', 'kestrel-birch' ); ?></span></button> | |
| 27 | 27 | </div> | |
| 28 | 28 | </div> |
WooCommerce: recipe slider-pause-control
Show the before and after (1)
assets/css/main.css Changes to assets/css/main.css: 28 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 508 | 508 | background: var(--kb-navy); | |
| 509 | 509 | } | |
| 510 | 510 | ||
| 511 | Added | /* validiscan:slider-pause-control */ | |
| 512 | Added | .hero-slider.is-paused .hero-slider__track { | |
| 513 | Added | animation-play-state: paused; | |
| 514 | Added | } | |
| 515 | Added | ||
| 516 | Added | @media (prefers-reduced-motion: reduce) { | |
| 517 | Added | .hero-slider__track { | |
| 518 | Added | animation-play-state: paused; | |
| 519 | Added | } | |
| 520 | Added | } | |
| 521 | Added | ||
| 522 | Added | .hero-slider__pause { | |
| 523 | Added | position: absolute; | |
| 524 | Added | top: 1rem; | |
| 525 | Added | right: 1rem; | |
| 526 | Added | z-index: 2; | |
| 527 | Added | min-height: 24px; | |
| 528 | Added | padding: 0.4em 0.9em; | |
| 529 | Added | border: 2px solid currentColor; | |
| 530 | Added | border-radius: 4px; | |
| 531 | Added | background: #ffffff; | |
| 532 | Added | color: var(--kb-ink); | |
| 533 | Added | font: inherit; | |
| 534 | Added | font-weight: 600; | |
| 535 | Added | cursor: pointer; | |
| 536 | Added | } | |
| 537 | Added | /* /validiscan:slider-pause-control */ | |
| 538 | Added | ||
| 511 | 539 | .hero-slide img { | |
| 512 | 540 | width: 100%; | |
| 513 | 541 | aspect-ratio: 5 / 2; |
assets/js/theme.js Changes to assets/js/theme.js: 20 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 255 | 255 | initCheckout(); | |
| 256 | 256 | initShowPassword(); | |
| 257 | 257 | })(); | |
| 258 | Added | ||
| 259 | Added | /* validiscan:slider-pause-control */ | |
| 260 | Added | (function () { | |
| 261 | Added | const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; | |
| 262 | Added | for (const slider of document.querySelectorAll('.hero-slider')) { | |
| 263 | Added | const button = slider.querySelector('.hero-slider__pause'); | |
| 264 | Added | if (!button) continue; | |
| 265 | Added | const pauseLabel = button.textContent; | |
| 266 | Added | const playLabel = button.getAttribute('data-play-label') || pauseLabel; | |
| 267 | Added | const set = (paused) => { | |
| 268 | Added | slider.classList.toggle('is-paused', paused); | |
| 269 | Added | button.textContent = paused ? playLabel : pauseLabel; | |
| 270 | Added | }; | |
| 271 | Added | button.addEventListener('click', () => { | |
| 272 | Added | set(!slider.classList.contains('is-paused')); | |
| 273 | Added | }); | |
| 274 | Added | if (reduce) set(true); | |
| 275 | Added | } | |
| 276 | Added | })(); | |
| 277 | Added | /* /validiscan:slider-pause-control */ |
template-parts/hero-slider.php Changes to template-parts/hero-slider.php: 1 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 37 | 37 | }; | |
| 38 | 38 | ?> | |
| 39 | 39 | <div class="hero-slider" data-autoplay="true" data-interval="6000"> | |
| 40 | Added | <button type="button" class="hero-slider__pause" data-play-label="<?php esc_attr_e( 'Play slideshow', 'kestrel-birch' ); ?>"><?php esc_html_e( 'Pause slideshow', 'kestrel-birch' ); ?></button> | |
| 40 | 41 | <div class="hero-slider__viewport"> | |
| 41 | 42 | <div class="hero-slider__track"> | |
| 42 | 43 | <?php |
Magento: recipe button-semantics
Show the before and after (1)
app/design/frontend/Validiscan/fixture/Magento_Cookie/templates/html/notices.phtml Changes to app/design/frontend/Validiscan/fixture/Magento_Cookie/templates/html/notices.phtml: 2 added, 2 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 24 | 24 | <div class="amgdprcookie-bar-block"> | |
| 25 | 25 | <p class="amgdprcookie-policy"><?= $escaper->escapeHtml(__('We use cookies to give you the best shopping experience and to analyse our traffic. By continuing to browse you agree to our')) ?> <a href="<?= $escaper->escapeUrl($block->getPrivacyPolicyLink()) ?>" class="amgdprcookie-link"><?= $escaper->escapeHtml(__('cookie policy')) ?></a>.</p> | |
| 26 | 26 | <div class="amgdprcookie-buttons-block"> | |
| 27 | Removed | <span class="amgdprcookie-button -allow" data-amcookie-js="allow" role="button" tabindex="0"><svg class="icon" viewBox="0 0 24 24"><path d="M4 12l5 5L20 6"/></svg></span> | |
| 28 | Removed | <span class="amgdprcookie-button -decline" data-amcookie-js="decline" role="button" tabindex="0"><svg class="icon" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18"/></svg></span> | |
| 27 | Added | <button class="amgdprcookie-button -allow" data-amcookie-js="allow" type="button"><svg class="icon" viewBox="0 0 24 24"><path d="M4 12l5 5L20 6"/></svg></button> | |
| 28 | Added | <button class="amgdprcookie-button -decline" data-amcookie-js="decline" type="button"><svg class="icon" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18"/></svg></button> | |
| 29 | 29 | </div> | |
| 30 | 30 | </div> | |
| 31 | 31 | </div> |
app/design/frontend/Validiscan/fixture/web/css/source/_theme.less Changes to app/design/frontend/Validiscan/fixture/web/css/source/_theme.less: 30 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1264 | 1264 | height: 18px; | |
| 1265 | 1265 | stroke-width: 3; | |
| 1266 | 1266 | } | |
| 1267 | Added | ||
| 1268 | Added | /* validiscan:button-semantics */ | |
| 1269 | Added | button.amgdprcookie-button.-allow, | |
| 1270 | Added | button.amgdprcookie-button.-decline { | |
| 1271 | Added | -webkit-appearance: none; | |
| 1272 | Added | appearance: none; | |
| 1273 | Added | margin: 0; | |
| 1274 | Added | padding: 0; | |
| 1275 | Added | box-shadow: none; | |
| 1276 | Added | font: inherit; | |
| 1277 | Added | letter-spacing: inherit; | |
| 1278 | Added | text-align: inherit; | |
| 1279 | Added | text-transform: inherit; | |
| 1280 | Added | text-shadow: none; | |
| 1281 | Added | } | |
| 1282 | Added | button.amgdprcookie-button.-allow:hover, | |
| 1283 | Added | button.amgdprcookie-button.-allow:focus, | |
| 1284 | Added | button.amgdprcookie-button.-allow:active { | |
| 1285 | Added | background: @nw-primary; | |
| 1286 | Added | border: 0; | |
| 1287 | Added | color: #fff; | |
| 1288 | Added | } | |
| 1289 | Added | button.amgdprcookie-button.-decline:hover, | |
| 1290 | Added | button.amgdprcookie-button.-decline:focus, | |
| 1291 | Added | button.amgdprcookie-button.-decline:active { | |
| 1292 | Added | background: #fff; | |
| 1293 | Added | border: 1px solid @nw-border; | |
| 1294 | Added | color: @nw-text; | |
| 1295 | Added | } | |
| 1296 | Added | /* /validiscan:button-semantics */ |
app/design/frontend/Validiscan/fixture/web/css/styles-m.css Changes to app/design/frontend/Validiscan/fixture/web/css/styles-m.css: 30 added, 0 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1232 | 1232 | height: 18px; | |
| 1233 | 1233 | stroke-width: 3; | |
| 1234 | 1234 | } | |
| 1235 | Added | ||
| 1236 | Added | /* validiscan:button-semantics */ | |
| 1237 | Added | button.amgdprcookie-button.-allow, | |
| 1238 | Added | button.amgdprcookie-button.-decline { | |
| 1239 | Added | -webkit-appearance: none; | |
| 1240 | Added | appearance: none; | |
| 1241 | Added | margin: 0; | |
| 1242 | Added | padding: 0; | |
| 1243 | Added | box-shadow: none; | |
| 1244 | Added | font: inherit; | |
| 1245 | Added | letter-spacing: inherit; | |
| 1246 | Added | text-align: inherit; | |
| 1247 | Added | text-transform: inherit; | |
| 1248 | Added | text-shadow: none; | |
| 1249 | Added | } | |
| 1250 | Added | button.amgdprcookie-button.-allow:hover, | |
| 1251 | Added | button.amgdprcookie-button.-allow:focus, | |
| 1252 | Added | button.amgdprcookie-button.-allow:active { | |
| 1253 | Added | background: #1979c3; | |
| 1254 | Added | border: 0; | |
| 1255 | Added | color: #fff; | |
| 1256 | Added | } | |
| 1257 | Added | button.amgdprcookie-button.-decline:hover, | |
| 1258 | Added | button.amgdprcookie-button.-decline:focus, | |
| 1259 | Added | button.amgdprcookie-button.-decline:active { | |
| 1260 | Added | background: #fff; | |
| 1261 | Added | border: 1px solid #c2c2c2; | |
| 1262 | Added | color: #333; | |
| 1263 | Added | } | |
| 1264 | Added | /* /validiscan:button-semantics */ |
Magento: recipe slider-pause-control
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: 1 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 3 | 3 | class="pagebuilder-slider slick-slider" | |
| 4 | 4 | data-content-type="slider" | |
| 5 | 5 | data-appearance="default" | |
| 6 | Removed | data-autoplay="true" | |
| 6 | Added | data-autoplay="false" | |
| 7 | 7 | data-autoplay-speed="3000" | |
| 8 | 8 | data-fade="false" | |
| 9 | 9 | data-infinite-loop="true" |
app/design/frontend/Validiscan/fixture/web/css/source/_theme.less Changes to app/design/frontend/Validiscan/fixture/web/css/source/_theme.less: 0 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1176 | 1176 | .slick-track { | |
| 1177 | 1177 | display: flex; | |
| 1178 | 1178 | width: 300%; | |
| 1179 | Removed | animation: nw-slider-autoplay 9s ease-in-out infinite; | |
| 1180 | 1179 | } | |
| 1181 | 1180 | .slick-slide { | |
| 1182 | 1181 | flex: 0 0 33.3333%; |
app/design/frontend/Validiscan/fixture/web/css/styles-m.css Changes to app/design/frontend/Validiscan/fixture/web/css/styles-m.css: 0 added, 1 removed
| Line before | Line after | Change | Code |
|---|---|---|---|
| 1147 | 1147 | .slick-track { | |
| 1148 | 1148 | display: flex; | |
| 1149 | 1149 | width: 300%; | |
| 1150 | Removed | animation: nw-slider-autoplay 9s ease-in-out infinite; | |
| 1151 | 1150 | } | |
| 1152 | 1151 | .slick-slide { | |
| 1153 | 1152 | flex: 0 0 33.3333%; |
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