Respecting prefers-reduced-motion
Detect the prefers-reduced-motion media query and disable or reduce animations for users who have requested less motion.
Respecting prefers-reduced-motion is a free Frontend Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The prefers-reduced-motion Media Feature
Some users experience nausea, dizziness, or seizures from motion in UIs. They set their OS to reduce motion. The prefers-reduced-motion media feature detects this preference so CSS can respond.
Detecting Reduced Motion in CSS
Wrap animations in the opposite query: apply animations normally, then override or disable them for users who prefer less motion.
/* Apply animation by default */
.spinner {
animation: spin 1s linear infinite;
}
/* Disable for users who want less motion */
@media (prefers-reduced-motion: reduce) {
.spinner {
animation: none;
}
}The 'Reduced Not None' Principle
prefers-reduced-motion: reduce doesn't mean no motion. Some motion conveys important UI state changes. Instead of removing animations entirely, slow them down or simplify them to crossfades.
@media (prefers-reduced-motion: reduce) {
.modal {
/* Replace scale + fade with just fade */
animation: fadeOnly 0.1s linear;
}
@keyframes fadeOnly {
from { opacity: 0; }
to { opacity: 1; }
}
}The Nuclear Option: Disable All Animations
A common pattern is to disable all transitions and animations globally for reduced-motion users. This is a safe baseline even if not every animation is tuned individually.
@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;
}
}Detecting Reduced Motion in JavaScript
Use the matchMedia API to detect the preference in JavaScript — useful for controlling canvas animations, JavaScript-driven motion, or video autoplaying.
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)');
if (prefersReduced.matches) {
// skip gsap or canvas animations
} else {
startAnimation();
}
// React to preference changes:
prefersReduced.addEventListener('change', (e) => {
if (e.matches) stopAnimations();
else startAnimations();
});Scroll Behaviour and Auto-Play
Also disable smooth scroll for reduced-motion users: scroll-behavior: auto. Stop auto-playing videos. Don't flash or strobe content.
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
// In JS:
if (!prefersReduced.matches) {
element.scrollIntoView({ behavior: 'smooth' });
} else {
element.scrollIntoView(); // instant
}WCAG 2.3.3 — Animation from Interactions
WCAG 2.3.3 (Level AAA) requires that motion triggered by user interaction can be disabled. By respecting prefers-reduced-motion, you satisfy this criterion and improve accessibility for users with vestibular disorders.
Testing Reduced Motion
In Chrome DevTools: open the rendering panel (three-dot menu → More tools → Rendering) and toggle 'Emulate CSS media feature prefers-reduced-motion'. Test your UI in this mode before shipping.
Practical: Safe Animation Pattern
A motion-safe animation applies by default and is wrapped so it's easy to disable globally.
@keyframes slideIn {
from { opacity: 0; transform: translateX(-16px); }
to { opacity: 1; transform: translateX(0); }
}
@media (prefers-reduced-motion: no-preference) {
.alert {
animation: slideIn 0.3s ease;
}
}Focus Animation Should Remain
Focus indicators (the ring that shows which element is focused) should NOT be removed even for reduced-motion users. They're essential for keyboard navigation and not typically vestibular triggers.
Libraries and prefers-reduced-motion
Popular animation libraries (Framer Motion, GSAP, Anime.js) have built-in support for reduced motion. Framer Motion's useReducedMotion() hook makes it easy to conditionally disable complex animations in React.
Quick Check
Which CSS media feature detects a user's preference to see less motion in the UI?
Recap: prefers-reduced-motion
Some users need less motion for vestibular and neurological health reasons. Use @media (prefers-reduced-motion: reduce) to disable or simplify animations. Detect in JS with matchMedia. The nuclear option: set animation/transition-duration to 0.01ms globally. WCAG 2.3.3 recommends it. Test with DevTools rendering panel.
Frequently asked questions
Is the “Respecting prefers-reduced-motion” lesson free?
Yes — the full text of “Respecting prefers-reduced-motion” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.
What will I learn in “Respecting prefers-reduced-motion”?
Detect the prefers-reduced-motion media query and disable or reduce animations for users who have requested less motion. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Frontend Academy?
No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Respecting prefers-reduced-motion” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Frontend Academy lesson?
Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- CSS Custom Properties: declaring and updating
- Transitions: property duration timing
- @keyframes Animations
- Respecting prefers-reduced-motion