CSS Reduced Motion & User Preferences: prefers-reduced-motion

CSS reduced motion lets you respect a user’s operating system or browser preference for less movement. It is an important accessibility feature because some animations, parallax effects, and transitions can cause discomfort or make interfaces harder to use.

Quick answer: Use the prefers-reduced-motion media feature to change or remove motion-heavy styles when the user has requested reduced motion. The most common pattern is @media (prefers-reduced-motion: reduce), which targets users who prefer less animation.

Difficulty: Beginner

You'll understand this better if you know: basic CSS selectors, how media queries work, and the difference between transitions, animations, and layout changes.

1. What Is CSS Reduced Motion & User Preferences?

Reduced motion is a CSS accessibility pattern that changes how your site animates when the user has asked for less movement at the system level. CSS exposes that preference through the prefers-reduced-motion media feature.

This is not the same as disabling all visual polish. The goal is to reduce unnecessary motion while keeping the interface clear and usable.

2. Why CSS Reduced Motion Matters

Motion can improve feedback, but too much movement can become an accessibility problem. Large zooms, sliding panels, bouncing elements, and parallax effects may make some people uncomfortable or make content harder to follow.

Using prefers-reduced-motion matters because it lets your interface adapt to the person using it. That is better than forcing the same motion on everyone.

It is especially important for:

When used well, reduced-motion styles still preserve meaning and feedback without relying on movement.

3. Basic Syntax or Core Idea

The core idea is simple: write normal motion styles first, then override them inside a media query for users who prefer reduced motion.

Minimal media query

The reduce value means the user has asked for less motion. The media query below is the foundation of most implementations.

@media (prefers-reduced-motion: reduce) {
  /* Reduced-motion styles go here */
}

This query only matches when the user has enabled the reduced-motion preference. If no preference is set, the rule does not apply.

Typical pattern with animation overrides

You often keep the design intact and simply remove or shorten motion inside the query.

.card {
  transition: transform 200ms ease, box-shadow 200ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .card {
    transition: none;
  }
}

This example keeps the component functional while removing motion for users who prefer a calmer experience.

4. Step-by-Step Examples

Example 1: Disabling a fade-in animation

A fade-in may look nice for most users, but it can be simplified when motion should be reduced.

.panel {
  animation: fade-in 300ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .panel {
    animation: none;
  }
}

The reduced-motion version removes the fade completely, which is often the safest choice when the animation is purely decorative.

Example 2: Shortening a transition instead of removing it

Sometimes motion still helps communicate state. In that case, reduce the duration rather than deleting the effect entirely.

.menu {
  transition: transform 250ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .menu {
    transition: transform 1ms linear;
  }
}

This keeps the state change understandable while making the motion effectively instant.

Example 3: Turning off a spinning loader

Continuous motion is one of the most common reduced-motion targets. A spinning loader can be simplified to a static indicator or text.

.spinner {
  animation: spin 1s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}

For accessibility, pair the visual spinner with text such as “Loading” so users still receive feedback when the animation is removed.

Example 4: Preventing large movement on page transitions

Sliding elements across the screen can be disorienting. A reduced-motion variant can keep the same layout without the movement.

.drawer {
  transform: translateX(100%);
  transition: transform 200ms ease;
}

.drawer.is-open {
  transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
  .drawer {
    transition: none;
    transform: none;
  }
}

This version removes the sliding motion so the drawer appears without sweeping across the viewport.

5. Practical Use Cases

Use reduced-motion styles in any interface where movement is part of the experience, especially when motion is decorative rather than essential.

If motion communicates meaning, try to preserve that meaning in a calmer form. If motion is purely ornamental, removing it is usually the right choice.

6. Common Mistakes

Mistake 1: Targeting the wrong preference value

Some developers write a media query that does not match the actual user preference. The result is that reduced-motion styles never apply when they should.

Problem: This query does not match users who prefer less motion, so the animation stays active.

@media (prefers-reduced-motion: no-preference) {
  .banner {
    animation: none;
  }
}

Fix: Use reduce when you want to adapt styles for users who prefer less motion.

@media (prefers-reduced-motion: reduce) {
  .banner {
    animation: none;
  }
}

The corrected query matches the preference you are trying to support.

Mistake 2: Removing motion but losing important feedback

Some animations are decorative, but some show progress or state. If you remove them without replacement, users can lose useful feedback.

Problem: The spinner disappears, but nothing else tells the user that work is happening.

.spinner {
  animation: spin 1s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    display: none;
  }
}

Fix: Keep a non-motion cue, such as text, a status message, or a static icon.

.loading {
  display: inline-flex;
  gap: 0.5rem;
}

.spinner {
  animation: spin 1s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}

The fixed version preserves feedback by leaving the loading message visible even when motion is reduced.

Mistake 3: Only changing animation but leaving transitions active

Motion is not limited to keyframe animations. Transition effects can also be a problem if they move large elements or change position abruptly.

Problem: The animation is removed, but the element still slides because the transition remains active.

.panel {
  animation: none;
  transition: transform 300ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .panel {
    animation: none;
  }
}

Fix: Override both animations and transitions when the motion effect is unnecessary.

@media (prefers-reduced-motion: reduce) {
  .panel {
    animation: none;
    transition: none;
  }
}

The corrected version removes both sources of movement, which is often what reduced-motion users expect.

7. Best Practices

Practice 1: Start with motion-safe defaults, then reduce motion selectively

Build the default experience first, then override only the parts that create discomfort. That keeps your CSS easier to maintain than writing two completely separate designs.

.modal {
  transition: opacity 200ms ease, transform 200ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .modal {
    transition: opacity 1ms linear;
    transform: none;
  }
}

This approach keeps the default interface polished while still respecting user preference.

Practice 2: Remove decorative motion first

If an animation does not communicate information, it is the best candidate for removal. Decorative motion often adds complexity without improving usability.

.hero-shape {
  animation: float 6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .hero-shape {
    animation: none;
  }
}

Users lose no essential information when decorative motion is removed.

Practice 3: Keep state changes understandable without relying on movement

Motion should not be the only signal that something changed. Color, visibility, text, and layout can also communicate state.

.tab {
  border-bottom: 2px solid transparent;
}

.tab.is-active {
  border-bottom-color: currentColor;
}

@media (prefers-reduced-motion: reduce) {
  .tab {
    transition: none;
  }
}

This makes the active state clear even when animation is reduced or removed.

8. Limitations and Edge Cases

If a motion effect is central to understanding the interface, make sure there is a non-motion fallback that conveys the same meaning.

9. Practical Mini Project

Let’s build a simple notification card that animates in normally but becomes static for users who prefer reduced motion. This small example shows the full pattern in context.

.notification {
  max-width: 28rem;
  padding: 1rem 1.25rem;
  border-radius: 0.75rem;
  background: #1f2937;
  color: #fff;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
  transform: translateY(0);
  animation: slide-in 300ms ease-out;
}

@keyframes slide-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .notification {
    animation: none;
    transform: none;
  }
}

This example shows the most common pattern: animated entrance by default, then a motion-free version for users who prefer reduced motion.

10. Key Points

11. Practice Exercise

Update the following card so that it respects reduced-motion preferences. The card should keep its content and state changes understandable without relying on movement.

Expected output: A card that still changes appearance on hover, but with little or no motion when the user prefers reduced motion.

Hint: Focus on transition and any movement created by transform.

.feature-card {
  padding: 1.5rem;
  border-radius: 1rem;
  background: #ffffff;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
  transition: transform 200ms ease, box-shadow 200ms ease;
}

.feature-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12);
}

@media (prefers-reduced-motion: reduce) {
  .feature-card {
    transition: box-shadow 1ms linear;
  }

  .feature-card:hover {
    transform: none;
  }
}

The solution keeps the hover state visible while removing the vertical movement for reduced-motion users.

12. Final Summary

CSS reduced motion is one of the clearest ways to make motion-sensitive users more comfortable without redesigning your whole interface. The prefers-reduced-motion media feature gives you a standard CSS-only way to detect the preference and adapt your animations and transitions.

In practice, the best reduced-motion styles are usually simple: remove decorative animation, shorten or eliminate movement, and keep important state changes understandable through other visual cues. That approach makes your interface calmer while preserving usability.

If you want to go further, review your site’s animations section by section and decide whether each motion effect is decorative, informative, or essential. That audit is often the fastest way to make a product feel more accessible.