Reducing Motion
For many people, motion on a screen can make them sick (opens in a new tab), cause seizures, significant distractability, and more. Fortunately, we have a feature in modern computing systems and browsers where we can make animation and transitions safer and more inclusive!
Reduced Motion was introduced a few years ago as a prefers-reduced-motion
(opens in a new tab) CSS Media Query and platform setting. It is supported (opens in a new tab) on Mac and iOS, Windows, and Android. With the ability to add a custom toggle to turn motion on or off, that means you can safely reduce motion pretty much anywhere.
Turning on Reduced Motion
On the MacOS System Preferences under Accessibility > Display, there is a toggle for "Reduce Motion". Turning this on or off will impact how CSS Media Queries and related JavaScript matchMedia functions in web browsers.
Using safe defaults
When you write your code for animation/transitions that will need Reduced Motion, you can go about it in a couple of ways:
- Non-animated by default, only moving if the setting exists and is unchecked (leveraging
prefers-reduced-motion: no-preference
)
@media (prefers-reduced-motion: no-preference) {
.mask {
/* do animation stuff */
}
}
- Animated by default, stopping movement if the setting exists and is checked (using
prefers-reduced-motion: reduce
)
@media (prefers-reduced-motion: reduce) {
.mask {
/* turn animations off */
animation: none;
transition: none;
}
}
It’s a slight difference. Only the first option will contribute to safe animation by default, no matter whether prefers-reduced-motion
is supported on the user’s device.
Example of the CSS media query
Here is an example of how to respond to reduced motion with CSS:
Example of the JavaScript matchMedia query
JavaScript also includes a function for matching the prefers-reduced-motion
media query. It is useful for times when your animations are created with JavaScript, video backgrounds, etc.
const motionQuery = matchMedia('(prefers-reduced-motion: no-preference)');
let userPrefersMotion = true;
function handleReduceMotionChanged() {
if (motionQuery.matches) {
/* adjust 'transition' or 'animation' properties */
userPrefersMotion = true;
} else {
/* standard motion */
userPrefersMotion = false;
}
}
motionQuery.addEventListener('change', handleReduceMotionChanged);
handleReduceMotionChanged(); // fire once on load
And here is an example using JavaScript matchMedia
: