Material-ui: Support for prefers-reduced-motion

Created on 25 Jun 2019  路  8Comments  路  Source: mui-org/material-ui

  • [x] This is not a v0.x issue.
  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 馃

The transition components Collapse, Fade, Grow, Slide, and Zoom (and other MUI components with animations) should have reduced motion in their animations, by either disabling the animations altogether or using a simple fade animation, when the prefers-reduced-motion: reduce media query is true.

Current Behavior 馃槸

None of the components change behaviour and show the same animation when the media query is true.

Examples 馃寛

Here鈥檚 the MDN doc for this media query. It鈥檚 supported on Chrome, Firefox, and Safari on Windows, Mac, and iOS.

This WebKit blog has several examples of how to support this media query.

Context 馃敠

I鈥檓 currently adding support for this media query in my web app by disabling page transitions and other custom transitions by using the media query in JSS. But I鈥檓 also using MUI鈥檚 built-in transition components and there is currently no easy way to disable those animations.

I could use the useMediaQuery hook to modify what my component returns to remove the transition components, but this is quite cumbersome. Supporting this media query directly would make it a lot easier to build more accessible web apps.

accessibility enhancement

Most helpful comment

Suggested here (https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/) to include something along the lines of:

@media screen and
  (prefers-reduced-motion: reduce), 
  (update: slow) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

Making note that,

Retaining the animation and transition duration also ensures that any functionality that is tied to CSS-based animation will activate successfully (unlike using a declaration of animation: none), while still preventing a disability condition trigger or creating rendering lag

Easy to include at the root of your app:

...

const useStyles = makeStyles(theme => ({
  root: {
    "@media (prefers-reduced-motion: reduce)": {
      "& *": {
        animationDuration: "0.001ms !important",
        animationIterationCount: "1 !important",
        transitionDuration: "0.001ms !important"
      }
    }
  },
}));

....
}

https://codesandbox.io/s/material-ui-prefer-reduced-motion-f1ljg

But I agree having built-in support would be best,

All 8 comments

Would the following be an acceptable solution?

import React from 'react';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import { ThemeProvider } from '@material-ui/core/styles';

function App() {
  const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');

  const theme = React.useMemo(
    () =>
      createMuiTheme({
        ...(prefersReducedMotion
          ? {
              // So we have `transition: none;` everywhere
              transitions: { create: () => 'none' },
            }
          : {}),
      }),
    [prefersReducedMotion],
  );

  return (
    <ThemeProvider theme={theme}>
      <Routes />
    </ThemeProvider>
  );
}

@oliviertassinari I'm guessing that doesn't affect the transition components? Fade, Grow, etc.

@joshwooding It does disable these components too.

An alternative with global CSS:

@media (prefers-reduced-motion: reduce) {
  * {
    animation-play-state: paused !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

I'm wondering 馃 I have seen it in https://hankchizljaw.com/wrote/a-modern-css-reset/ (BTW, there are potential good resets we can deploy in CssBasline for v5).

Hey @oliviertassinari, just to confirm: would your solution be something I鈥檇 have to add to each of my React projects using MUI?

@notseenee Regarding your question. Should we have built-in support for the preferred reduced motion preference? Yes, I think that we should explore this path, it sounds better.

@oliviertassinari Yep, I think it鈥檚 in the interest of users and developers to have built-in support for prefers-reduced-motion as opposed to making devs implement it themselves

Suggested here (https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/) to include something along the lines of:

@media screen and
  (prefers-reduced-motion: reduce), 
  (update: slow) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

Making note that,

Retaining the animation and transition duration also ensures that any functionality that is tied to CSS-based animation will activate successfully (unlike using a declaration of animation: none), while still preventing a disability condition trigger or creating rendering lag

Easy to include at the root of your app:

...

const useStyles = makeStyles(theme => ({
  root: {
    "@media (prefers-reduced-motion: reduce)": {
      "& *": {
        animationDuration: "0.001ms !important",
        animationIterationCount: "1 !important",
        transitionDuration: "0.001ms !important"
      }
    }
  },
}));

....
}

https://codesandbox.io/s/material-ui-prefer-reduced-motion-f1ljg

But I agree having built-in support would be best,

Was this page helpful?
0 / 5 - 0 ratings