Guide

How to verify web motion accessibility.

Motion is one of the few accessibility areas where a defect can make users physically ill, and it's routinely skipped in audits because it doesn't show up in a static screenshot. This guide walks through verifying the animation layer of any web page: what the relevant WCAG criteria actually require, how to test them by hand, and which code patterns pass.

Step 1 — Inventory every source of motion

Before judging motion you have to find it. Web animation comes from four places:

  • CSS animationsanimation / @keyframes rules in linked stylesheets and <style> blocks.
  • CSS transitionstransition rules that fire on state changes (hover, focus, class toggles).
  • The Web Animations API and JS librarieselement.animate(), GSAP, anime.js and friends; these live in JavaScript and are invisible to a CSS-only scan.
  • Animated media — autoplaying video, animated GIFs/WebP, canvas and WebGL scenes.

Grep the codebase for animation, transition, @keyframes, animate(, and autoplay, and note which elements they touch. On a page you don't own, the browser DevTools "Animations" panel records everything that actually runs.

Step 2 — Test prefers-reduced-motion for real

Users signal motion sensitivity through an operating-system setting, which the browser exposes as the prefers-reduced-motion media feature. Turn it on and reload the page:

  • macOS: System Settings → Accessibility → Display → Reduce motion. Windows: Settings → Accessibility → Visual effects → Animation effects off. iOS/Android: the equivalent Accessibility toggle.
  • Faster, in DevTools: Chrome/Edge — Rendering panel → "Emulate CSS media feature prefers-reduced-motion: reduce". Firefox and Safari offer equivalents.

Everything decorative should stop or reduce to a crossfade. Anything still moving that isn't essential to the content is a finding. "Essential" is narrow: a video the user asked to play is essential; a floating hero graphic is not.

Step 3 — Check the three WCAG criteria that govern motion

WCAG 2.2.2 — Pause, Stop, Hide (Level A)

Any moving, blinking or scrolling content that starts automatically, lasts longer than five seconds, and sits alongside other content needs a way to pause, stop, or hide it. Infinite spinners, marquees, and auto-rotating carousels without a pause control fail this. It's a Level A requirement — the baseline conformance level. Understanding 2.2.2

WCAG 2.3.1 — Three Flashes or Below Threshold (Level A)

Nothing may flash more than three times per second above the defined brightness/area thresholds; this is the photosensitive-seizure criterion, also Level A. Rapid blinking badges and strobing effects are the typical offenders. Understanding 2.3.1

WCAG 2.3.3 — Animation from Interactions (Level AAA)

Motion triggered by interaction (scroll-linked effects, parallax, animated page transitions) should be disableable unless essential — in practice: honor prefers-reduced-motion. Note the level honestly: 2.3.3 is AAA, the highest, optional tier — it is not part of the usual Level AA conformance target. Treating it as a hard requirement overstates the law; treating it as ignorable overstates your users' tolerance. Understanding 2.3.3

Step 4 — Apply code patterns that pass

The core pattern: make "no motion" the default and opt into animation only when the user hasn't asked for reduced motion.

/* CSS: animate only when the user has NOT requested reduced motion */
@media (prefers-reduced-motion: no-preference) {
  .card { animation: rise 0.5s ease-out; }
  .hero { transition: transform 0.3s ease; }
}
// JS: guard every scripted animation the same way
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
  el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300 });
}

For content under 2.2.2, pair the guard with a real pause path — for example a button that sets animation-play-state: paused on the moving element (that's the pattern this site's own "Reduce motion" button uses).

Pitfalls we see constantly: guarding only some stylesheets while a component library ships unguarded keyframes; "disabling" motion by shortening durations to 200ms instead of removing it; listening for the media query once at load and ignoring changes; and forgetting that GIFs and autoplay video are motion too — the media query won't touch them.

Step 5 — Automate the CSS part (optional)

Steps 1–4 are manual and cover everything. If you want the CSS portion automated, our free motion check statically scans any URL's linked CSS and style blocks against WCAG 2.2.2 and 2.3.3 and shows each finding with a suggested fix. Honest scope: it's a static scan — runtime JS/GSAP motion isn't covered, it's not a full accessibility audit, and it's not a compliance verdict. Nothing you submit is stored. What it can't see, steps 1–4 catch.

A note on compliance

No guide and no tool makes a site "compliant" by itself. Which rules legally apply to you (EAA, national law, sector rules) depends on your situation, and overall conformance depends on far more than motion. What this process gives you is the motion layer done right — verified, not assumed. Background reading: What is motion slop?

Scan the CSS part in ten seconds.

Paste any URL into the free motion check — every finding with the fix, no signup, nothing stored.

Run the free motion check