Skip to main content

Why reduced motion matters

Animations can be quite distracting to people that suffer from vertigo, have ADHD, or just have a high sensitivity to motion. For some users, excessive motion and animations can cause:
  • Vertigo and dizziness - Spinning or parallax effects can trigger vestibular disorders
  • Nausea - Rapid movements or transitions may cause physical discomfort
  • Distraction - Constant motion makes it difficult to focus on content (particularly for users with ADHD)
  • Cognitive overload - Too many moving elements can overwhelm users with processing difficulties
  • Seizures - In extreme cases, certain animations can trigger seizures
Motion-triggered accessibility issues are not just about preference - they can make your website physically unusable for some people.
As developers, we need to make sure we minimize (or completely remove) distracting animations whenever possible.

The prefers-reduced-motion media query

A good way to make sure we are not distracting our users is to respect their reduced motion preferences. Modern operating systems allow users to indicate their motion preferences in their system settings. We can detect this preference using the CSS prefers-reduced-motion media query.

How it works

/* Default: animations enabled */
.element {
  animation: spin 2s infinite;
  transition: transform 0.3s ease;
}

/* When user prefers reduced motion: disable or reduce animations */
@media (prefers-reduced-motion: reduce) {
  .element {
    animation: none;
    transition: none;
  }
}

Browser support

The prefers-reduced-motion media query is supported in all modern browsers including Chrome, Firefox, Safari, and Edge.

Implementing reduced motion in CSS

There are several approaches to implementing reduced motion support in your stylesheets.

Approach 1: Disable animations selectively

Disable animations on specific elements that could be problematic:
.spinner {
  animation: spin 1s linear infinite;
}

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

Approach 2: Global animation reset

Disable all animations and transitions globally:
@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;
  }
}
The global approach is useful as a baseline, but you may want to keep some subtle animations for important state changes.

Approach 3: Reduce instead of remove

For some animations, completely removing them might reduce usability. Instead, consider reducing their intensity:
.button {
  transition: transform 0.3s ease, background 0.3s ease;
}

.button:hover {
  transform: scale(1.1);
  background: blue;
}

@media (prefers-reduced-motion: reduce) {
  .button {
    /* Keep color transition but remove transform */
    transition: background 0.3s ease;
  }
  
  .button:hover {
    transform: none;
  }
}

Real-world example from the course

The Web A11y for Devs course demonstrates reduced motion support on button elements:
button {
  padding: 0.5rem 1rem;
  border: 1px solid var(--brand-secondary);
  color: var(--brand-secondary);
  border-radius: 5px;
  cursor: pointer;

  &:hover {
    background: var(--brand-primary);
    border-color: var(--brand-primary);
    color: white !important;
  }

  &:active {
    scale: 0.95 !important;
  }

  /* Eliminate redundant transitions for users that don't want them */
  @media (prefers-reduced-motion: reduce) {
    transition: none !important;
  }
}

Best practices for animations

Implement prefers-reduced-motion for all significant animations. This is not optional - it’s an accessibility requirement.
Instead of removing all feedback, replace heavy animations with simpler alternatives like opacity changes or subtle color transitions.
Continuous spinning, bouncing, or flashing elements are particularly problematic. If you must use them, ensure they can be paused or disabled.
Enable reduced motion in your system settings and test your site. Does it still feel responsive and provide adequate feedback?
Some animations improve usability, like smooth scrolling to error messages or highlighting newly added items. You may keep these but reduce their duration or intensity.
CSS animations are easier to control with media queries and typically perform better.

Enabling reduced motion in your OS

To test your implementations, enable reduced motion in your system settings:
  1. Open Settings
  2. Go to Accessibility > Visual effects
  3. Toggle off “Animation effects”

JavaScript detection

You can also detect motion preferences in JavaScript:
const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches;

if (prefersReducedMotion) {
  // Disable or reduce animations
  console.log('User prefers reduced motion');
} else {
  // Enable full animations
  console.log('User is okay with animations');
}

Listening for changes

Users can change their preferences while your site is open:
const motionMediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');

function handleMotionPreferenceChange(event) {
  if (event.matches) {
    // User now prefers reduced motion
    disableAnimations();
  } else {
    // User now allows motion
    enableAnimations();
  }
}

motionMediaQuery.addEventListener('change', handleMotionPreferenceChange);

Exercise: Implement reduced motion

Practice exercise

In the Web A11y for Devs course, there’s a spinner that continuously rotates. Your task is to disable this animation when users have reduced motion preferences enabled.File: src/exercises/reduced-motion/reduced-motion.cssTask: Add CSS to stop the spinner animation when prefers-reduced-motion: reduce is true.The spinner HTML:
<div
  id="spinner"
  aria-hidden="true"
  class="h-10 w-10 animate-spin rounded-full border-4 border-l-transparent"
></div>
Hint: Use the @media (prefers-reduced-motion: reduce) query to target the spinner and set animation: none.

Common mistakes to avoid

Don’t assume reduced motion means removing all visual feedback. Users still need to know when actions succeed or fail.
  • Removing all transitions - Some transitions aid usability (like smooth state changes)
  • Breaking functionality - Ensure interactive elements still work without animations
  • Ignoring parallax effects - These are particularly problematic and should always be disabled
  • Forgetting scroll behavior - Also set scroll-behavior: auto in your reduced motion styles
  • Not testing - Always test with reduced motion enabled in your system

Additional resources

Build docs developers (and LLMs) love