Skip to main content

Command Palette

Search for a command to run...

Respect reduced motion (Web HIG tip #9)

Updated
•4 min read•View as Markdown

A slide-in panel looks smooth to most people. For someone with a vestibular disorder, it can bring on dizziness or nausea. Their OS already has a "Reduce motion" setting. Your CSS should listen to it.

Web HIG tip #9 (Quick #76 / HIG-A11Y-001): Respect prefers-reduced-motion — replace motion with instant state changes or minimal opacity fade.

Why it matters

Motion that's fine for one person can make another feel sick:

  • People with vestibular disorders, migraines, or motion sensitivity turn on "Reduce motion" so large on-screen movement stops making them unwell

  • Parallax, big slide-ins, zooming page transitions, and auto-playing carousels cause the most trouble

  • If the page ignores the setting, people have no way to stop it, so they leave

  • The fix is small: the browser already exposes the setting as a media query

The full HIG (§1.3, Reduced Motion & Animation Safety) makes this a mandatory HIG requirement, even though the matching WCAG criterion (2.3.3 Animation from Interactions) is Level AAA. Auto-playing carousels and looping motion also need a pause control under WCAG 2.2.2 Pause, Stop, Hide (Level A).

The rule of thumb

Ask: with "Reduce motion" turned on, does anything still slide, zoom, spin, or scroll by itself?

If yes, swap that motion for an instant change or a short fade.

/* Don't: the panel always slides in, whatever the user's setting */
.panel {
  transform: translateX(100%);
  transition: transform var(--duration-slow) var(--ease-out-momentum);
}
.panel.is-open {
  transform: none;
}

/* Do: keep the slide by default, and swap it for a short fade when reduced motion is on */
@media (prefers-reduced-motion: reduce) {
  .panel {
    transform: none;
    opacity: 0;
    visibility: hidden; /* a closed panel must not catch clicks or focus */
    transition: opacity var(--duration-base) linear,
                visibility 0s linear var(--duration-base);
  }
  .panel.is-open {
    opacity: 1;
    visibility: visible;
    transition-delay: 0s;
  }
}

Motion started from JavaScript needs the same check:

document.querySelector("#to-pricing").addEventListener("click", () => {
  // Check at click time, so a setting changed mid-session is respected
  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  document.querySelector("#pricing").scrollIntoView({
    behavior: reduceMotion ? "instant" : "smooth",
  });
});

Use "instant", not "auto": "auto" follows your CSS scroll-behavior, so a site with html { scroll-behavior: smooth } would still glide.

Reduced motion doesn't mean no feedback. A button can still change color and a dialog can still fade in. What goes is the movement: sliding, scaling, bouncing, parallax, and smooth scrolling.

Do this instead

  • Wrap slide, scale, and parallax effects so they're replaced under prefers-reduced-motion: reduce

  • Use an instant state change or a minimal opacity fade as the reduced version, so the user still sees that something changed

  • Turn off parallax, auto-playing carousels, decorative looping animations, and View Transitions morphing when reduced motion is on. Immersive storytelling surfaces have a narrow exception (§1.5), and they still need a calm equivalent

  • Check the same setting in JavaScript before smooth scrolling or starting an animation

  • Name the properties you animate instead of using transition: all (Quick #85, tip #6), so it's clear what your reduced-motion rules need to cover

Quick check for your app

Turn on reduced motion: in Chrome DevTools, press Cmd/Ctrl+Shift+P, run "Show Rendering", and set "Emulate CSS media feature prefers-reduced-motion" to reduce, or use your OS setting. Then open a menu and a dialog, trigger a page transition, and click an in-page link. Nothing should slide, zoom, or smooth-scroll, and every state change should still be visible. A media query existing isn't the same as the motion actually calming down, so test it.

HIG.md §1.3 also includes a global CSS safety net that cuts animation and transition durations and turns off smooth scrolling under reduced motion. Treat it as a backstop, not a replacement for a calm version of each effect.


The Web HIG is a behavioral contract for how the web should behave, not a component library. Design systems define how it looks. The Web HIG defines how it behaves.