Transitions what are they good for?

Transitions help to show the user what is changing, motion attracts the eye and helps to draw attention to the changing content. It also adds a feeling of skeuomorphic real-world cause and effect. Hover/focus states help to indicate what is and what isn't an interactive element. In the case of internal page links, smooth scrolling helps to orient the user to where the target content is in relation to where they where on the page. Historically, smooth scrolling wasn't preferred as it made the browser's 'Find in page' functionality slower and harder to use, but now as many browsers don't apply smooth scrolling anymore when users search page content, smooth scrolling is becoming more and more common.

What if the user doesn't want motion?

Our users may have requested reduced motion for some pretty serious reasons, for example, vestibular disorder. So it's important we disable motion for those users. Not everyone is a fan of things moving around so let's not force it on them, fortunately, we can turn off transitions and animations in the CSS using the prefers-reduced-motion media query. Browser support is growing (See Can I Use). There is still a little way to go on mobile, but I'm sure it will catch up with desktop before too long.

CSS

In CSS the prefers-reduced-motion media query.

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

JS

And in JS you can check with the window.matchMedia method.

const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion)').matches;
if (!prefersReducedMotion) {
  // animate stuff
}

Let's take a moment to look at a really annoying thing...

<style>
  :root {
    --animation-duration: 2s;
  }
  @media (prefers-reduced-motion: reduce) {
    :root {
      --animation-duration: 0;
    }
  }

  .annoying-thing {
    animation: annoy var(--animation-duration) cubic-bezier(0.3, 0.05, 0.2, 0.8) infinite;
    display: inline-block;
    transform: translate(0, 0) rotate(0deg) scale(1);
  }

  @keyframes annoy {
    10%, 90% { transform: translate(-1px, 1px) rotate(-8deg); }
    20%, 80% { transform: translate(2px, -2px) rotate(8deg); }
    30%, 50%, 70% { transform: translate(5px, -5px) rotate(-8deg) scale(1.05); }
    40%, 60% { transform: translate(-2px, 2px) rotate(8deg); }
  }
</style>
<div class="annoying-thing">Really annoying thing!</div>
Really annoying thing!

So that's annoying, let's request reduced motion (example shown is in MacOS, System Preferences > Accessibility > Display) checking this option should stop the above animation running.

Mac OS accessibility menu showing Reduce motion setting

As we have seen to respect the user's preferences in the CSS we need to use the prefers-reduced-motion media query. For transitions setting the duration to 0 will just mean it snaps to the new state without any motion. For animations setting the animation duration to 0 will prevent animations from playing at all so this is a good place to start. As another option, we could set the animation-play-state to paused instead of the default running. To prevent smooth scrolling set the scroll-behavior to auto. Bearing the above in mind, our CSS might end up looking something like this...

:root {
  --animation-duration: 1s;
  --transiton-duration: 0.5s;
}
html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --animation-duration: 0;
    --transiton-duration: 0;
  }
  html {
    scroll-behavior: auto;
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* styles here for any parallax effects */
}

Critical animations

With transitions an element is usually just going nicely from one state to another, removing the transition won't interfere with the user's understanding of the page. However, with animations this might not always be the case. When setting an animation's duration to 0 it's likely the animation won't play at all so if using animation-fill-mode: forwards we would need to consider what the default state for that element should be and set it manually. Or if an animation is the only visual clue of what is happening, e.g. clicking a 'Buy Now' button triggers an animation that drops an item into a virtual basket, when we remove the animation we'll need to make sure there is some other way to notify the user the basket has been updated.

Don't forget testing ♥

When testing we should remember to give our sites the once over with reduced motion preferred. Simply disabling transitions/animations and smooth scrolling when the user has requested reduced motion isn't hard and we should take the time to make the web as an inclusive space as possible.

Resources and Further Reading