docs/react-v9/contributing/rfcs/react-components/convergence/disabling-animations.md
@miroslavstastny
This RFC describes how animations and transitions in Fluent UI components can be disabled.
Before adding motion tokens to react-theme, we should know how to disable applications during runtime. V8 has
not had a feature disable animations, whereas V0 leverages is CSS in JS framework to strip animations at runtime.
An application needs a way to disable animations due to following reasons:
Users can choose to disable animations in application settings:
There is currently no known requirement to reduce motion (use less or slower/faster animations).
The recommended solution will involved both Fluent and consumer Apps.
prefers-reduced-motion media queryFor animations/transitions in Fluent, we should leverage the prefers-reduced-motion media query. All animations that should be toned down within Fluent should declare an alternative style using the media query. This is the same approach that we follow with high contrast mode proposed in #17465.
The below sample code is available on a demo in codesandbox.
import { Button, ButtonProps, makeStyles } from '@fluentui/react-components';
import * as React from 'react';
const useStyles = makeStyles({
animations: {
animationDuration: '2s',
animationTimingFunction: 'linear',
animationIterationCount: 'infinite',
animationFillMode: 'both',
'@media(prefers-reduced-motion)': {
animationName: {
'0%': {
opacity: 1,
},
'50%': {
opacity: 0.8,
},
'100%': {
opacity: 1,
},
},
},
animationName: {
'0%': {
transform: 'scale(1)',
},
'25%': {
transform: 'scale(0.9)',
},
'50%': {
transform: 'scale(1)',
},
'75%': {
transform: 'scale(1.1)',
},
'100%': {
transform: 'scale(1)',
},
},
},
});
const Example = (props: ButtonProps) => {
const styles = useStyles();
return (
<Button appearance="primary" className={styles.animations}>
Example
</Button>
);
};
We recommend users to use the prefers-reduced-motion, since that gives cross platform support without addtional performance costs of specific selectors or JavaScript runtime. Additionally, not all animations need to be disabled, and limited animations like colour change are still acceptable for users that need reduced motion.
As an escape hatch, applications can add a CSS rule with !important property which will override all the animations and transitions on the page. This can
be done on the application side, and will impact all non-Fluent UI styles. This can be useful for browser screenshot
tests that should not screenshot the state of an animation.
*,
*::before,
*::after {
animation-delay: -1ms !important;
animation-duration: 1ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
transition-duration: 0.1s !important;
transition-delay: 0.1s !important;
}
This global CSS approach is also recommended by MUI. We go further by overriding animation duration to imperceptible levels so that we don't break features that use animation events, this is recommended by this blog post.
Codesandbox: https://codesandbox.io/s/disable-animations-important-dpugv
DOMRendererFilter out animation* and transition* CSS properties before adding them to DOM.
Stardust uses this approach to disable disable animations. The linked solution does not handle transition, only animation.
Similar implementation is doable with Griffel, there is unstable_filterCSSRule in DOMRenderer - with that we can filter out all transition and animation CSS properties.
Codesandbox: https://codesandbox.io/s/disable-animations-filter-80d4i
makeStyles no matter whether tokens or direct values have been used to style the animation.makeStyles (inline style).All animations are supposed to be styled using theme tokens, including the animation timings. To disable the animations, we can set all the tokens for duration to 0.