notes
May 17, 2025 · 2 min read

Auditing Every Animation for Reduced Motion

prefers-reduced-motion is one line in a media query, which makes it easy to assume you’ve handled it once and move on. I made that assumption for months. Then I actually turned the setting on in my OS and clicked around my own site, and found four separate places where something still moved.

What I found

  • The card hover “pop” — the up-left translate with the shrinking shadow — ignored the setting entirely and still ran at full speed.
  • The scroll-reveal fade-and-rise had a reduced-motion fallback for the transform, but not for the opacity fade, so cards still faded in gradually instead of appearing instantly.
  • The nav link bounce respected the setting on hover but not on focus, so keyboard navigation — which is disproportionately used by people who also have motion sensitivity settings enabled — got the full animation anyway.
  • A page transition cross-fade I’d added more recently simply hadn’t been tested against the setting at all, because I wrote it after the last time I did this audit.

The pattern behind all four

Every one of these was written correctly for the feature and incompletely for the setting — I’d think about reduced motion when writing the primary interaction and forget it existed by the time I got to a secondary state like focus, or a feature I added three months after the original component.

@media (prefers-reduced-motion: reduce) {
  .card,
  .nav-link,
  [data-reveal] {
    transition: none !important;
    animation: none !important;
    transform: none !important;
  }
}

Why one pass isn’t enough

The uncomfortable conclusion is that this isn’t a checkbox I get to tick once. Every new interactive element is a new place the setting can be forgotten, because it’s an easy thing to write correctly by accident on the happy path and just as easy to leave broken on the path you didn’t personally test. The fix going forward isn’t a smarter one-time audit — it’s a line in the review checklist for literally every future animation, and an actual OS-level toggle test before I consider one done.