WebCraft

prefers-reduced-motion

Less motion is not no motion

your system asks for full motion, so the dot orbits

your system asks for reduced motion: the spin is gone, a slow fade stays

CaveatThe query reports a vestibular accessibility setting, not a taste in animation — what triggers the symptoms is movement: spins, parallax, zooms, things travelling across the screen. An opacity crossfade is almost always safe to keep, which is why the word in the query is reduced. The blanket animation: none !important has a trap of its own: an animation that never runs never reaches its end state and never fires animationend, so the element that was going to fade in stays invisible and the listener waits forever. The safer blanket shrinks every duration to a frame — the end state and the event still land, only the journey is gone.

FallbackAn engine too old to know the query plays full motion for everyone, including the people the setting exists for. Writing it the other way round — motion gated behind (prefers-reduced-motion: no-preference), stillness as the default — flips that: anything unknown gets the still version. Which default is right depends on who is worse off getting the wrong one, and for anything that swings or spins the answer is the still one.

CSS
@media (prefers-reduced-motion: reduce) {
  /* a frame, not none: end states
     and animationend still land */
  *, *::before, *::after {
    animation-duration:
      .01ms !important;
    animation-iteration-count:
      1 !important;
    transition-duration:
      .01ms !important;
  }
}

Published