Reduce motion, don’t delete it

Under reduced motion, drop movement but keep the fades.

From improve-animations: missing reduced motion is MEDIUM.

One drawer, three policies

Open the drawer, then drag the fade length.

Reduce: nuke allBad
transition: none !important
Reduce: toned downGood
opacity 200ms ease-out
No preferenceFull motion
transform 300ms var(--ease-drawer)
.drawer { transform: translateY(100%); transition: transform 300ms var(--ease-drawer); }
.drawer[data-open] { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .drawer { transform: none; opacity: 0; transition: opacity 200ms ease-out; }
  .drawer[data-open] { opacity: 1; }
}

Hover scale on touch

Simulate touch, tap both cards, then tap elsewhere.

False hovers: 0
Ungated :hoverBad
.card:hover { scale: 1.05 }
Gated to fine pointerGood
@media (hover: hover) and (pointer: fine)

Branch the transform in JS

Send a toast, toggle reduced motion, send again.

Ignores the settingBad

No toasts yet

y: "100%" → 0, always
Branches on itGood

No toasts yet

y: "100%" → 0, 300ms
const reduce = useReducedMotion();

<motion.div
  initial={reduce ? { opacity: 0 } : { y: "100%" }}
  animate={reduce ? { opacity: 1 } : { y: 0 }}
  transition={{ duration: reduce ? 0.2 : 0.3, ease: [0.23, 1, 0.32, 1] }}
/>

Why it matters, pros and cons

Why it matters

Movement causes discomfort, not fades. Keep the cue that something changed.

Pros

  • Reduced-motion users keep state feedback.
  • One media query per component.
  • No stuck, enlarged cards on phones.

Cons

  • Large fades can still bother some users; keep them short.
  • Per-component handling is easier to miss than a global reset.
  • Hybrid devices report only the primary pointer.