CSS Motion and Accessibility: Using prefers-reduced-motion
CSS motion can make interfaces feel polished and responsive, but it can also be distracting or uncomfortable for some users. This article explains how to respect motion preferences with prefers-reduced-motion, when to reduce animation, and how to design motion that stays accessible.
Quick answer: Use the CSS media query @media (prefers-reduced-motion: reduce) to provide a calmer version of your animations and transitions. Keep the interface usable without motion, and never rely on animation for essential information.
Difficulty: Beginner
You'll understand this better if you know: basic CSS selectors, how transitions and animations work, and the purpose of media queries.
1. What Is Motion Accessibility?
Motion accessibility means designing animations, transitions, and other moving effects so they do not create barriers for people who are sensitive to motion. The main CSS tool for this is the user preference media query prefers-reduced-motion.
- It lets the browser tell you when the user has asked for less motion.
- It helps reduce discomfort for users with vestibular or motion sensitivity.
- It supports calmer interfaces without removing visual polish for everyone.
- It affects both transition and animation patterns.
In practice, you do not remove all movement from the web. You provide a reduced-motion alternative that avoids unnecessary movement, large zooming effects, and long animated transitions.
2. Why Motion Accessibility Matters
Some users experience dizziness, nausea, headaches, or concentration issues when interfaces move too much. A parallax effect, scrolling animation, or sudden zoom can be uncomfortable even if the design looks attractive to others.
Supporting reduced motion is important because it:
- respects the user's operating system or browser preference,
- improves comfort for motion-sensitive users,
- reduces accidental attention stealing in interfaces with lots of movement,
- helps teams build accessibility into motion design from the start.
Motion accessibility matters most when movement is decorative, large-scale, or repeated often. If motion communicates status or helps explain a state change, it should be kept subtle and still remain understandable without animation.
3. Basic Syntax or Core Idea
The core technique is a media query that checks whether the user prefers reduced motion. Inside that query, you can shorten transitions, stop animations, or replace movement-heavy effects with simpler styles.
Minimal pattern
Start with a normal animated style, then override it for users who prefer less motion.
.card {
transition: transform 250ms ease;
}
.card:hover {
transform: translateY(-4px);
}
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
}
}
This pattern keeps the default behavior for most users and provides a motion-light version for users who request it.
4. Step-by-Step Examples
Example 1: Reducing a hover transition
Hover effects often use short transitions. For reduced motion, removing the animated shift can make the interaction feel stable while still keeping the hover state visible through color or outline.
.button {
background: #2563eb;
color: #fff;
transition: transform 180ms ease, background-color 180ms ease;
}
.button:hover {
transform: translateY(-2px);
background-color: #1d4ed8;
}
@media (prefers-reduced-motion: reduce) {
.button {
transition: background-color 120ms ease;
}
.button:hover {
transform: none;
}
}
The reduced version keeps the visual state change but removes the movement.
Example 2: Turning off a repeating animation
Infinite or repeated animations are more likely to bother motion-sensitive users. In reduced motion mode, replacing them with a static indicator is usually better than keeping a looped animation.
.loader {
width: 2rem;
height: 2rem;
border: 4px solid #cbd5e1;
border-top-color: #2563eb;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.loader {
animation: none;
border-top-color: #94a3b8;
}
}
Here the spinning motion disappears, but the loader still has a visible presence.
Example 3: Replacing a slide-in panel
Sliding panels can feel like objects moving across the screen. For reduced motion, it is often better to fade in quickly or show the panel without movement.
.panel {
opacity: 0;
transform: translateX(24px);
transition: opacity 240ms ease, transform 240ms ease;
}
.panel.is-open {
opacity: 1;
transform: none;
}
@media (prefers-reduced-motion: reduce) {
.panel {
transition: opacity 120ms linear;
transform: none;
}
}
The reduced-motion version avoids the sideways movement while still revealing the panel clearly.
Example 4: Respecting animated page sections
Some sites animate content into view. If you use those effects, make sure the content is still fully readable and usable when motion is removed.
.feature {
opacity: 0;
transform: translateY(16px);
transition: opacity 300ms ease, transform 300ms ease;
}
.feature.is-visible {
opacity: 1;
transform: none;
}
@media (prefers-reduced-motion: reduce) {
.feature {
transition: opacity 150ms ease;
transform: none;
}
}
This keeps the content accessible even if the scroll-triggered motion is toned down or removed.
5. Practical Use Cases
Use prefers-reduced-motion when motion is decorative or could be distracting. Common situations include:
- button hover effects that move elements slightly,
- loading spinners and pulsing indicators,
- modal, drawer, and panel entrances,
- scroll-linked or parallax-like effects,
- animated cards, alerts, and onboarding hints,
- full-screen transitions between app states.
It is especially useful in product interfaces, dashboards, e-commerce sites, marketing pages with animated sections, and content-heavy applications where users spend a long time reading.
6. Common Mistakes
Mistake 1: Removing motion entirely for everyone
Some developers disable animation globally because they think accessibility means no motion at all. That can make the site feel less clear for users who benefit from gentle feedback.
Problem: This approach removes all transitions for all users, even when motion is small and helpful.
* {
animation: none;
transition: none;
}
Fix: Keep the default motion and override it only inside the reduced-motion media query.
@media (prefers-reduced-motion: reduce) {
* {
animation: none;
transition: none;
}
}
The corrected version respects the user's preference instead of changing the experience for everyone.
Mistake 2: Hiding important state changes inside animation
Another common issue is using motion to communicate something essential, such as an element appearing, an error arriving, or a status changing. If motion is removed, the state can become unclear.
Problem: The content depends on animation to be noticed, so reduced-motion users may miss the change entirely.
.message {
opacity: 0;
transform: translateY(20px);
transition: opacity 300ms ease, transform 300ms ease;
}
.message.is-visible {
opacity: 1;
transform: none;
}
Fix: Make the visible state clear even without movement, and use motion only as a enhancement.
.message {
opacity: 0;
}
.message.is-visible {
opacity: 1;
}
@media (prefers-reduced-motion: no-preference) {
.message {
transform: translateY(20px);
transition: opacity 300ms ease, transform 300ms ease;
}
}
The fix keeps the state understandable even when animation is reduced.
Mistake 3: Keeping long or repeated animations in reduced mode
Not all motion has the same impact. Long-duration or infinite animations are much more likely to cause discomfort than a brief color transition.
Problem: The animation still runs in reduced motion, so the interface does not actually respect the user's preference.
@media (prefers-reduced-motion: reduce) {
.banner {
animation: slideGlow 6s ease-in-out infinite;
}
}
Fix: Remove the repeated motion or replace it with a static style change.
@media (prefers-reduced-motion: reduce) {
.banner {
animation: none;
box-shadow: none;
}
}
This version removes the repeated effect and keeps the banner visually stable.
7. Best Practices
Practice 1: Design motion as an enhancement, not a dependency
Motion should make the interface nicer, not necessary for understanding it. Build the layout so the content is clear before animation runs.
.dialog {
opacity: 1;
transform: none;
}
@media (prefers-reduced-motion: no-preference) {
.dialog {
opacity: 0;
transform: scale(0.98);
transition: opacity 200ms ease, transform 200ms ease;
}
}
This approach keeps the base state accessible even when motion is reduced.
Practice 2: Prefer short, subtle motion when it is helpful
Short transitions are usually less likely to be problematic than large movement or repeated loops. Use them for lightweight feedback like color changes or tiny shifts.
.tab {
transition: color 150ms ease, border-color 150ms ease;
}
Subtle motion is easier to tolerate and more likely to remain usable for a wider range of people.
Practice 3: Remove movement before removing meaning
If you have to simplify an effect, keep the visual information and remove the movement first. A static style change is often enough.
.toast {
opacity: 0;
}
.toast.is-open {
opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
.toast {
transition: opacity 120ms ease;
}
}
This keeps the notification understandable without making it feel jumpy.
8. Limitations and Edge Cases
- prefers-reduced-motion is a user preference, not a guarantee that every motion-sensitive person has it enabled.
- Some browsers or environments may not expose the preference in the same way, so the base experience should still be safe.
- Reduced motion does not mean reduced clarity. You still need visible state changes, focus styles, and good contrast.
- Very small transitions, such as a short color fade, may still be acceptable, but repeated motion can become tiring even when it is subtle.
- CSS alone can only adapt the styles you control. If your interface relies on non-CSS movement patterns, you need to design those systems carefully too.
One practical rule is simple: if the effect makes the page harder to follow, or if it exists mostly for decoration, provide a reduced-motion alternative.
9. Practical Mini Project
Here is a small card component that uses motion for polish, but remains calm when reduced motion is requested. The default version animates slightly on hover; the reduced version removes movement and keeps only a color-based change.
.product-card {
padding: 1.25rem;
border: 1px solid #dbe3ea;
border-radius: 0.75rem;
background: #fff;
transition: transform 200ms ease, box-shadow 200ms ease;
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
}
@media (prefers-reduced-motion: reduce) {
.product-card {
transition: box-shadow 120ms ease;
}
.product-card:hover {
transform: none;
box-shadow: 0 0 0 2px #2563eb;
}
}
This example is useful because it keeps the interaction readable, attractive, and motion-aware at the same time.
10. Key Points
- prefers-reduced-motion lets CSS respond to a user's motion preference.
- Use it to reduce or remove decorative movement, not to make interfaces less clear.
- Keep the default experience usable even if the user never enables the preference.
- Replace motion with static style cues such as color, opacity, outline, or spacing when needed.
- Test repeated, large, or sliding effects first because they are the most likely to cause problems.
11. Practice Exercise
- Create a content card that fades in on hover with a slight upward shift.
- Add a reduced-motion version that removes the shift but keeps a visible hover state.
- Make sure the card still looks interactive without any animation.
Expected output: A card that feels animated for most users, but remains stable and accessible when reduced motion is requested.
Hint: Use color, border, or shadow changes to preserve feedback after removing transform.
Solution:
.exercise-card {
padding: 1rem;
border: 1px solid #cbd5e1;
border-radius: 0.5rem;
background: #ffffff;
transition: transform 180ms ease, border-color 180ms ease;
}
.exercise-card:hover {
transform: translateY(-3px);
border-color: #2563eb;
}
@media (prefers-reduced-motion: reduce) {
.exercise-card {
transition: border-color 120ms ease;
}
.exercise-card:hover {
transform: none;
border-color: #2563eb;
}
}
This solution works because the hover state remains obvious even after the movement is removed.
12. Final Summary
CSS motion accessibility is about making animations and transitions safer and more comfortable without giving up good design. The key tool is prefers-reduced-motion, which lets you detect when a user wants less motion and adjust your styles accordingly.
The best approach is to keep motion optional, subtle, and decorative. Make sure the interface remains understandable without animation, and use static cues such as color, spacing, opacity, and outline to communicate state when motion is reduced.
If you want to go further, review your site's transitions, loading states, and entrance animations one by one and decide which ones can be simplified for reduced-motion users.