Open notsidney opened 5 years ago
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’d 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’s 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,
Commenting here to resurface this issue. Also, +1 for built in support :)
Can we please have this built-in?
Being someone who suffers from motion sensitivity, it immediately stood out to me. And since MUI is almost screaming off the rooftops its support for accessibility features, you can imagine my dampened enthousiasm about a11y when I saw the first transition ever so smoothly giving me my next headache.
I sure hope MUI isn't giving us motion sensitive people an unearned finger, but it looks like that, frankly, seeing how this issue is from 2019. It doesn't take four years to get a fairly simple a11y feature into your framework, does it. If it does, then please explain why it's difficult. Maybe I can help.
Would this apply to the Skeleton component as well? I don't want the loading animation to run when reduced-motion is enabled.
@IDrumsey Yeah, this would make sense to me. Maybe to make the animation run more slowly rather that entierely disabled?
reduce Indicates that a user has enabled the setting on their device for reduced motion. This keyword value evaluates as true.
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
@oliviertassinari I was thinking more along the lines of completely disabling the animation in case people have motion sensitivity. I'm currently just using a hook right now to check if reduced-motion is enabled and the manually setting the animation=
based on that. Would be good if this was just built into the component.
@IDrumsey Completely disabling animations is the correct way to respond to this setting. I too don't understand why W3C calls it "reduce" (and "prefers" - as it's not a preference, it's accessibility), because there's no way of knowing by how much to reduce. Depends on the user's level of sensitivity. For me personally, only "big" animations are problematic, so a small loader spinner is fine. But a screen-sized menu sliding into the page, or a full page dim for a dialog, those are not okay. There are, however, many people much more sensitive than me, who can't even handle a small spinning loader icon.
It's the reason why Firefox at some point decided to even make the spinning loader in a tab a static icon when the OS reports animations are disabled. Even I wouldn't have thought that to trigger a response in anyone, but it did, and they fixed it.
HOWEVER, please bare in mind that by removing animations, you potentially introduce another problem: flashing images. So a fading animation removed turns into a flashing image. That's great for me, but now you've created a problem for people sensitive to flashing lights/images (epilepsy). This can happen (at least by default) for animationless dialogs that have a dimmed backdrop, for example.
@oliviertassinari Slowing down an animation makes it worse for me.
Completely disabling animations is the correct way to respond to this setting.
@thany macOS behaves differently, see my recording:
https://github.com/mui/material-ui/assets/3165635/b3f60b09-9eed-4067-9535-99274dd48f76
@oliviertassinari It depends on the form of sensitivity one is suffering from. I for one, cannot handle motion, but crossfades are less of a problem. Other people might still have a problem with crossfades.
The safest course of action is to disable all forms of animation, because we've only got the one switch to flip. We haven't got separate switches for motion, flashing lights, and crossfades, have we? 🙂
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’s the MDN doc for this media query. It’s 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’m 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’m also using MUI’s 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.