Your Animations Might Be Making People Sick
A colleague once told me she had to close my demo page because the scroll-triggered zoom effects made her dizzy - she has a vestibular disorder, and screen motion she didn't initiate triggers genuine nausea and disorientation. That group is not small, and every major OS ships a "reduce motion" setting for exactly this reason. Our job is to listen to it.
The CSS side
The blunt-but-effective global rule I ship in every project:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Why 0.01ms instead of none? Because JavaScript listening for animationend / transitionend still fires - animations complete instantly rather than never, so UI that waits on them doesn't hang. That detail has saved me from reduced-motion-only bugs more than once.
The more surgical approach is opt-in per effect, and it reads nicely inverted:
@media (prefers-reduced-motion: no-preference) {
.hero-img { animation: float 6s ease-in-out infinite; }
html { scroll-behavior: smooth; }
}
Written this way, no motion preference = no fancy motion, and the animation is the enhancement. That's the right default posture.
The JavaScript side
const prefersReduced = matchMedia('(prefers-reduced-motion: reduce)');
function scrollToTop() {
window.scrollTo({ top: 0, behavior: prefersReduced.matches ? 'auto' : 'smooth' });
}
prefersReduced.addEventListener('change', updateCarouselAutoplay);
The change listener matters: users toggle the OS setting live, and well-behaved pages respond without a reload. (More matchMedia patterns in this tutorial.) Autoplaying carousels, particle backgrounds, scroll-jacking - these should pause entirely under reduce.
What to reduce vs. remove
"Reduced" doesn't mean "dead interface". The consensus that's emerged:
- Remove or minimize: parallax, zoom/scale transitions, auto-playing motion, anything that moves large areas or simulates depth. These are the vestibular triggers.
- Fine to keep: instant state changes, opacity fades (crossfades don't trigger vestibular responses for most people), small color transitions. A 150ms opacity fade on a dropdown is fine; the dropdown flying in from off-screen is not.
Test it yourself: macOS Settings → Accessibility → Display → Reduce motion; Windows Settings → Accessibility → Visual effects → Animation effects off. Then browse your site. Ten minutes, and you'll know exactly where you stand - most sites fail within the first scroll.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.