Stephen Lindberg

Product Designer @ Iterable

15 August 2020

Respecting Motion Preferences

Animations and transitions can bring richness to web experiences. They can provide continuity and help people understand interfaces in more nuanced ways. However, motion can be jarring or inaccessible for some people. You can use the media query prefers-reduced-motion to control whether animations are active or not.

For example, you could disable all motion:

@media (prefers-reduced-motion) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

This is an extreme example which may break parts of your website or app. In order to maintain accessibility, consider:

  1. Include fallbacks to indicate state changes that don’t rely on animation.
  2. Make sure your components are functional given the default styling.

To elaborate on that second point with an example: you may have a component which animates into the window after a delay. If the initial state of the component is off-screen, then the component will never be visible if its animation is disabled. You can rectify this by making the default state be on-screen, and define an animation which moves the component from off-screen to on-screen, pairing that with a rule to preserve the “extremes” of the animation:

.slide-in {
  animation-fill-mode: both;
  /* … */
}

But what if there are some subtle animations that you don’t want to get rid of with this wholesale solution? One way is to limit the selector to ignore a data-attribute, like so:

@media (prefers-reduced-motion) {
  *:not([data-preserve-motion]) {
    animation: none !important;
    transition: none !important;
  }
}

and HTML:

<div class="my-subtle-animation" data-preserve-motion></div>

So that’s a simple way to rework your animations and transitions to respect user preferences. If you are building something from scratch, you could tailor animations to move less or animate in a more subtle way if a user prefers reduced motion.