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 !importantReduce: toned downGood
opacity 200ms ease-outNo 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, alwaysBranches on itGood
No toasts yet
y: "100%" → 0, 300msconst 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.