Animations should respect the reduced-motion setting

Large moving, zooming or parallax effects can make people with vestibular disorders dizzy or nauseous. They switch on "reduce motion" in their device settings, and a shop that ignores the setting can drive them away.

Rule id
vs-motion
Source
Validiscan check
Impact
Minor
Fix tier
AUTO
on Shopify, Shopware, WooCommerce and Magento
Status
runs

What the check does

Detects CSS and script animations, parallax and zoom effects that ignore the prefers-reduced-motion user setting. Reported as best practice (related to 2.3.3 Animation from Interactions, level AAA); flashing content is covered by the manual checklist (2.3.1).

Pages load with no motion preference. The check reads computed animation and transition properties of up to 5,000 elements in the body, ignoring hidden ones. Candidates are running CSS animations that repeat forever or have an animation-duration over 5 seconds, and transitions over 5 seconds.

The page is switched to prefers-reduced-motion: reduce, scripts get 150 ms to react, and every candidate is reread. One that is removed, paused, hidden, or made finite and 5 seconds or shorter passes, even through a cross-origin stylesheet. The rest become findings, at most 20 per page. If the switch fails, a prefers-reduced-motion query in a stylesheet defining or applying the animation counts as a guard.

An autoplaying video goes to needs review unless the setting hides it, or pauses it while playing. So does one reminder to check flashing by hand if the page shows video, canvas, .gif images or animation. The scanner does not turn needs review into findings today. Motion a script drives frame by frame is not measured.

How to fix it

Wrap non-essential animations and transitions in @media (prefers-reduced-motion: no-preference), or switch them off inside @media (prefers-reduced-motion: reduce), and check the setting in JavaScript before starting animations.

WCAG success criteria

Best practice: not tied to a WCAG success criterion.

Where a recipe fixes it

Shopify: recipe reduced-motion-guard

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

assets/base.css.liquid Changes to assets/base.css.liquid: 13 added, 0 removed

Changes to assets/base.css.liquid: 13 added, 0 removed
Line before Line after Change Code
1866 1866 }
1867 1867
1868 1868 /* ----------------------------------------------------------------- motion */
1869 Added
1870 Added /* validiscan:reduced-motion-guard */
1871 Added @media (prefers-reduced-motion: reduce) {
1872 Added *,
1873 Added *::before,
1874 Added *::after {
1875 Added animation-duration: 0.01ms !important;
1876 Added animation-iteration-count: 1 !important;
1877 Added transition-duration: 0.01ms !important;
1878 Added scroll-behavior: auto !important;
1879 Added }
1880 Added }
1881 Added /* /validiscan:reduced-motion-guard */

Shopware: recipe reduced-motion-guard

Show the before and after (1)
guards the pulsing badge and the slider autoplay; the animation stops under reduce Example data

Resources/app/storefront/src/main.js Changes to Resources/app/storefront/src/main.js: 1 added, 1 removed

Changes to Resources/app/storefront/src/main.js: 1 added, 1 removed
Line before Line after Change Code
139 139 });
140 140 });
141 141
142 Removed if (options.autoplay === true) {
142 Added if (options.autoplay === true && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
143 143 window.setInterval(
144 144 function () {
145 145 show(current + 1);

Resources/app/storefront/src/scss/base.scss Changes to Resources/app/storefront/src/scss/base.scss: 14 added, 0 removed

Changes to Resources/app/storefront/src/scss/base.scss: 14 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:reduced-motion-guard */
1713 Added /* Honour the visitor's reduced-motion setting: animations and transitions end at once, no smooth scrolling. */
1714 Added @media (prefers-reduced-motion: reduce) {
1715 Added *,
1716 Added *::before,
1717 Added *::after {
1718 Added animation-duration: 0.01ms !important;
1719 Added animation-iteration-count: 1 !important;
1720 Added transition-duration: 0.01ms !important;
1721 Added scroll-behavior: auto !important;
1722 Added }
1723 Added }
1724 Added /* /validiscan:reduced-motion-guard */

WooCommerce: recipe reduced-motion-guard

Show the before and after (1)
guards the looping hero slide and sale badge animations of the fixture theme Example data

assets/css/main.css Changes to assets/css/main.css: 13 added, 0 removed

Changes to assets/css/main.css: 13 added, 0 removed
Line before Line after Change Code
794 794 color: #999;
795 795 cursor: pointer;
796 796 }
797 Added
798 Added /* validiscan:reduced-motion-guard */
799 Added @media (prefers-reduced-motion: reduce) {
800 Added *,
801 Added *::before,
802 Added *::after {
803 Added animation-duration: 0.01ms !important;
804 Added animation-iteration-count: 1 !important;
805 Added transition-duration: 0.01ms !important;
806 Added scroll-behavior: auto !important;
807 Added }
808 Added }
809 Added /* /validiscan:reduced-motion-guard */

Magento: recipe reduced-motion-guard

Show the before and after (1)
guards the badge and slider animations and validates Example data

app/design/frontend/Validiscan/fixture/web/css/source/_theme.less Changes to app/design/frontend/Validiscan/fixture/web/css/source/_theme.less: 9 added, 0 removed

Changes to app/design/frontend/Validiscan/fixture/web/css/source/_theme.less: 9 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:reduced-motion-guard */
1269 Added @media (prefers-reduced-motion: reduce) {
1270 Added .product-label,
1271 Added .slick-track {
1272 Added animation: none;
1273 Added }
1274 Added }
1275 Added /* /validiscan:reduced-motion-guard */

app/design/frontend/Validiscan/fixture/web/css/styles-m.css Changes to app/design/frontend/Validiscan/fixture/web/css/styles-m.css: 9 added, 0 removed

Changes to app/design/frontend/Validiscan/fixture/web/css/styles-m.css: 9 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:reduced-motion-guard */
1237 Added @media (prefers-reduced-motion: reduce) {
1238 Added .product-label,
1239 Added .slick-track {
1240 Added animation: none;
1241 Added }
1242 Added }
1243 Added /* /validiscan:reduced-motion-guard */

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