Respect prefers-reduced-motion

Check reduced motion in CSS and JS; swap big motion for a fade.

From nextjs-pagespeed.

Motion: full

Parallax and a count-up

Play intro, then tick Simulate reduce and replay.

Ignores the settingBad
Collected in September$48,250
–
Checks matchMediaGood
Collected in September$48,250
–
const motion = matchMedia("(prefers-reduced-motion: reduce)");
if (motion.matches) {
  counter.textContent = format(TARGET);
  fadeIn(layers, 200);
} else {
  flyIn(layers);
  countUp(counter, TARGET);
}

CSS obeys, JavaScript forgets

Tick Simulate reduce, then press Send.

Media query onlyBad
Draft Client
–
CSS + matchMediaGood
Draft Client
–
@media (prefers-reduced-motion: reduce) {
  .toast { transform: none; }
}
if (motion.matches) place(dot, 1);
else tween(600, (p) => place(dot, p));

Read once vs subscribe

Press Start, then toggle Simulate reduce.

Read at loadBad
Syncing
const REDUCE = mq.matches;rotate: off
Listens for changeGood
Syncing
mq.addEventListener("change", …)rotate: off
motion.addEventListener("change", () => {
  motion.matches ? stopLoop() : startLoop();
});

Why it matters, pros and cons

Why it matters

Parallax and long travel can make vestibular users sick; JS must ask matchMedia.

Pros

  • One listener, near-zero cost.
  • Reduced path does less main-thread work.
  • Content is readable at once.

Cons

  • Reduce is not remove; keep explanatory fades.
  • Two paths to test, or one rots.
  • User-driven motion, like a drag, can stay.