How to Use prefers-reduced-motion in WordPress Themes

January 3, 2026
How to Use prefers-reduced-motion in WordPress Themes

Animations can improve perceived quality, but they can also cause discomfort for some users.
Operating systems provide an accessibility setting called “Reduce Motion”, and browsers expose it via the
CSS media query prefers-reduced-motion.

A WordPress theme should respect this setting by reducing or disabling non-essential motion
while keeping the UI functional.
This is both an accessibility best practice and a practical way to avoid animation-related jank on low-end devices.

What prefers-reduced-motion Does

prefers-reduced-motion can be:

  • reduce: the user requests less motion
  • no-preference: the user has not requested reduced motion

Your theme should:

  • Remove or simplify decorative animations (parallax, long transitions, auto-sliding carousels)
  • Keep essential state changes (open/close menus) but make them instant or minimal
  • Avoid smooth scrolling when reduce motion is enabled

1) CSS: Disable or Reduce Animations and Transitions

A common baseline is to disable animations and reduce transition duration when motion is reduced.

/* Respect Reduce Motion */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

This is a “global kill switch”. It’s effective, but may be too aggressive if you rely on specific transitions.
For more control, scope it to your theme components.

2) CSS: Target Only Theme Components (Recommended)

Instead of applying to every element, limit it to your UI parts: menus, accordions, modals, hero animations.

@media (prefers-reduced-motion: reduce) {
  .site-header,
  .site-nav,
  .modal,
  .accordion,
  .hero {
    animation: none !important;
    transition: none !important;
  }

  html:focus-within {
    scroll-behavior: auto;
  }
}

This keeps third-party widgets or embedded components from being unexpectedly affected.

3) CSS: Replace Motion with Non-Motion Feedback

If you remove animations, you may still want visual affordances.
Use color/opacity changes without movement.

@media (prefers-reduced-motion: reduce) {
  .button,
  .nav a {
    transition: color 0.01ms linear, background-color 0.01ms linear, opacity 0.01ms linear;
  }
}

4) JavaScript: Detect Reduced Motion and Disable Animation Logic

If your theme uses JavaScript for animations (IntersectionObserver effects, sliders, GSAP, etc.),
you should also respect the preference in JS.

function wpctPrefersReducedMotion() {
  return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

if (wpctPrefersReducedMotion()) {
  // Disable or skip non-essential animations.
} else {
  // Initialize animations normally.
}

5) JavaScript: Handle Preference Changes Live

Users can change accessibility settings while the page is open (rare, but possible).
You can listen for changes:

var mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');

function onMotionPreferenceChange() {
  if (mediaQuery.matches) {
    // Turn off animation features
  } else {
    // Turn on animation features
  }
}

if (mediaQuery.addEventListener) {
  mediaQuery.addEventListener('change', onMotionPreferenceChange);
} else if (mediaQuery.addListener) {
  mediaQuery.addListener(onMotionPreferenceChange);
}

This ensures your UI stays consistent with user preferences.

6) WordPress-Friendly Pattern: Add a Body Class

If you want a consistent switch in CSS without repeating media queries,
you can add a body class via a tiny inline script.
This is optional, but useful when you have many components.

Enqueue an Inline Script in WordPress

<?php
add_action( 'wp_enqueue_scripts', function () {
  if ( is_admin() ) {
    return;
  }

  // Ensure your main script is enqueued first.
  wp_enqueue_script( 'theme-script', get_template_directory_uri() . '/assets/js/main.js', array(), '1.0.0', true );

  $inline = <<<JS
(function () {
  if (!window.matchMedia) return;
  var mq = window.matchMedia('(prefers-reduced-motion: reduce)');
  function apply() {
    document.documentElement.classList.toggle('reduce-motion', mq.matches);
  }
  apply();
  if (mq.addEventListener) mq.addEventListener('change', apply);
  else if (mq.addListener) mq.addListener(apply);
})();
JS;

  wp_add_inline_script( 'theme-script', $inline, 'before' );
}, 20 );

Then in CSS:

.reduce-motion .hero,
.reduce-motion .modal {
  transition: none !important;
  animation: none !important;
}

This can be easier to maintain than repeating media queries everywhere.

7) Common Theme Features to Adapt

Smooth Scrolling

If you enable smooth scrolling globally, disable it for reduced motion:

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

Scroll-Based Reveal Animations

When reduced motion is enabled, render elements “already visible”.

/* Default hidden state for reveal */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 300ms ease, transform 300ms ease;
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

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

Auto-Playing Sliders

Disable autoplay when reduced motion is enabled, or provide a pause control.
If your slider is custom JS, gate the autoplay:

var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var autoplay = reduce ? false : true;

Testing Checklist

  • Enable Reduce Motion in OS settings (macOS/iOS/Windows)
  • Test key UI: mobile menu, modal open/close, accordion
  • Ensure no “stuck” hidden states (opacity 0, transform offsets)
  • Confirm smooth scrolling is disabled under reduce motion

Common Mistakes

  • Disabling motion but leaving elements hidden (opacity 0) with no alternative state
  • Applying a global kill switch that breaks third-party widgets
  • Forgetting JS-driven animations (CSS-only fixes won’t help)
  • Keeping autoplay enabled on sliders for reduced-motion users

Summary

  • prefers-reduced-motion is an accessibility setting that themes should respect
  • Use CSS media queries to disable non-essential animations and smooth scrolling
  • Gate JavaScript animation logic using matchMedia
  • Optionally add a reduce-motion class for easier maintenance
  • Always ensure components remain functional with motion removed

By respecting reduced motion, your WordPress theme becomes more accessible, more stable, and often faster—
without giving up modern UI patterns.

Avatar

Written by

satoshi

I’ve been building and customizing WordPress themes for over 10 years. In my free time, you’ll probably find me enjoying a good football match.