Open jensimmons opened 5 years ago
Here is another variant I have encountered (not tested):
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0s !important;
transition: none !important;
scroll-behavior: auto !important;
}
}
I found the tweets I snagged this code from... by @scottjehl
The Media Queries 5 spec defines prefers-reduced-motion
here:
https://drafts.csswg.org/mediaqueries-5/#descdef-media-prefers-reduced-motion
The issue where this CSS feature was created is here: https://github.com/w3c/csswg-drafts/issues/442
There's a bit of discussion about enforcing this with the browser itself, but that idea was set aside:
The core reason this needs to expose a user preference rather than change something about the view is because UI varies greatly. There's no way a UA can reliably reduce or stop motion on behalf of the user and still guarantee an understandable interface. Exposing the pref gives authors a way to do this appropriately within the context of their own interfaces.
Reading the debate in the CSSWG issue is a good way to think about the use cases and options.
I'm left thinking we should include this in Remedy, not because the CSSWG "got it wrong", but because this is a good default for all of the web developers (Authors) who don't bother thinking about prefers-reduced-motion
at all. It gives people who need animations eliminated or reduced what they need. And while this might potentially 'break' some UX, developers can easily fix those less-frequent cases by overriding Remedy's code.
Now if we could only make this apply to all the auto-play video/gif/animated advertisements. (UA's should enforce this by turning all gifs and videos into NOT autoplaying. Can we do that in the CSSWG @frivoal @fantasai ?)
Oh, which still leaves the question of how.... (I just also want to consider if, for a bit, too / think about why the CSSWG didn't put the burden of this on the browser to enforce.)
How about this? transition-timing-function: steps(1, start) !important; animation-timing-function: steps(1, start) !important;
No, CSS does not have control over autoplay.
Setting both transition/animation to none and transition/animation-duration to 0 seems redundant?
Setting transition/animation: none
might break animations using the FLIP model, so *-duration: 0s
would be more robust in light of that.
That said, an at-the-time WebKit engineer cautioned me against this sort of CSS when I mentioned it on Twitter 2 years ago:
Both of those are likely overkill, and depending on the context, could cause usability problems.
So this might be a thornier issue than it first seems.
@tigt
It won't just break animations using the FLIP model. It would break anything using a transitionEnd
or animationEnd
event.
For instance: to detect from the JavaScript side when an element has changed state of one of its properties; or to detect that it has just switched from invisible to visible/rendered state.
The second in particular is a necessity for a few complicated solutions. Including some strategies used to polyfill or provide fallback solutions for the ResizeObserver
API. You don't want to mess with this by specifying !important
styles and start off a specificity war...
This is definitely a more complex problem than it initially seems as has been stated above. In my research so far I haven't found a blanket solution that isn't without issues. But trying for a "least risky" option to include in this reset could provide a decent starting point. (And help spread knowledge that such a media query exists.)
Most have been mentioned in this thread already, but here's a summary based on my research so far that might be helpful for this decision:
The almost 0s duration:
animation-duration: 0.001s !important;
transition-duration: 0.001s !important;
animation-fill-mode
of forwards
or both
may never be visible. (An animation-fill-mode:forwards !important
could be added, but would also have its own potential issues.) opacity
of 0, or positioned out of view, would never be visible .Based on this test, animation events still fire, but the timing of when they fire may still be an issue for some uses.
This nearly 0s duration approach might be an acceptable way to go for this project. It’s not without issues or risks, but if it can be assume that this base stylesheet is being implemented at the beginning of a project, the author could be encouraged to compose all CSS-based animations with this reduced rule in mind from the start. (Admittedly, that is still a big assumption.)
none:
animation: none !important;
transition: none !important;
Very short duration:
animation-duration: 0.1s !important;
transition-duration: 0.1s !important;
Steps:
transition-timing-function: steps(1, start) !important;
animation-timing-function: steps(1, start) !important;
Two other points to consider:
Whatever this rule ends up being, it will be favoring stopping all animation by default which can be beyond what is needed in many situations. Both the WebKit blog post onprefers-reduced-motion
and the WCAG point out that not all kinds of animation are potentially triggering, and define criteria for animations that should be reduced when requested.
prefers-reduced-motion
can be respected for JS animation as well, but that would be separate effort. The combination of reduced CSS-based motion and non-reduced JavaScript motion could result in usability problems as well.
Thank you Val.
So, to be clear,
animation-duration: 0s !important;
transition-duration: 0s !important;
is likely a bad solution, because in certain browsers, the state change will never happen. So, for example, if someone has applied a fade to a hover color, instead of immediately getting the hover color (rather than a fade), with a 0 duration, the user might get no hover color — things just staying without a color change at all.
So that's off the table. It's good to know why.
Seems to me like we should do this:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001s !important;
transition-duration: 0.001s !important;
}
}
and nothing else is required. (Unlike the recent code in the project that was more complex.
There are many, many situation where that won't work, but it's also likely that 90% of websites only use animations at this point for things like hover color transitions, and other slight details. Hopefully anyone building more complex animations will know to think through what happens when prefers-reduced-motion: reduce
is applied.
In fact, the alarm that people might have from us doing this might generate enough buzz and conversation that the message will get around. Pay attention to prefers-reduced-motion: reduce
. Don't just allow the default from Remedy or other similar projects.
The other choice is to not do this at all. To leave it all up to the developers. I just don't like that. I'd rather risk breaking fancy animations than risk no websites bothering to write good code for people who can't take motion very well.
(And I say this as one of those people — motion on websites makes me nauseous. Really any looping motion, like repeating animated gifs in conference presentations. Ugh. Sadly, this setting will not help with the worst problems — ads with motion. Reader Mode is the only solution to that, atm.)
Sadly using !important
will make it hard to override this default. If anyone has ideas about that, let's discuss. If I were a developer planning to do a lot of animation, it's likely I'd fork Remedy, and remove this code in order to not be stuck trying to override an !important statement. Not everyone will have the ability to do that.
I'm going to change the code. Let's keep talking about it.
Should the code also apply to ::before
, ::after
, and other pseudo-elements? (Though, I think ::first-line
and friends only accepting certain typography-based styles means they don’t allow transition
and animation
set directly on them.)
@valhead What do you think about pseudo-elements?
Two additional note on the 0.001s
duration idea:
0s
causes trouble for keyframe animations in Safari, adding animation-iteration-count: 1 !important
would prevent that repeating freak-out state from happening.
0.01s
would serve the same purpose and is shorter.Applying the rule to ::before
and ::after
seems smart. Those are often used in animations.
Related to your button hover example, @jensimmons : It looks like a 0s
duration on transitions still functions in Safari (test here), so the 0.01s
would only be needed for CSS keyframe animations written with implied styles for the 0% (and possibly other) keyframes.
Adjusting for not allowing infinitely repeating animations and the fact that only keyframe animations appear to fail with the 0s
duration in Safari:
animation-duration: 0.01s !important;
animation-iteration-count: 1 !important;
transition-duration: 0s !important;
For animation, what if the duration was set to a really large value instead of a really small value to effectively pause it? On that note, animation-play-state: paused
will do this.
@media (prefers-reduced-motion: reduce) {
* {
animation-play-state: paused !important;
transition: none !important;
}
}
animation: none
will break is related to a project I’m working on a project now. It leverages CSS animations for spacial, not time, based events. A paused state would be ideal to not break animations used to display things that aren’t time based. A similar technique could be used to blend two CSS variables like tint a primary color (pause an animation between var(--primary)
and white
).
This still may run into the case of animations that start by hiding content through opacity: 0
or off screen. Therefore pausing the content in an unavailable state.
Thoughts on this? I’m liking @valhead’s direction but modified with a delay to fast forward the animation.
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-delay: -1s !important;
animation-duration: 1s !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01s !important;
}
}
example here: https://codepen.io/scottkellum/pen/YogBVM?editors=1100
In addition to animations and transitions, I too, think the impact of scroll-behavior: smooth
as suggested by https://github.com/mozdevs/cssremedy/issues/11#issuecomment-460455224 should be strongly considered.
Also, here's an opinion on parallax motion effect due to background-attachment: fixed
from
https://alistapart.com/article/accessibility-for-vestibular/:
there are no words to describe just how bad a simple parallax effect, scrolljacking, or even
background-attachment: fixed
would make me feel. I would rather jump on one of those 20-G centrifuges astronauts use than look at a website with parallax scrolling.
So perhaps:
*,
::before,
::after {
background-attachment: initial !important;
}
Was there an explicit decision made not to include scroll-behavior: auto !important;
? Disabling potential scroll-behavior: smooth
occurrences could be just as important (if not more so, particularly on long pages) than perhaps other types of motion through animation/transition/background-attachment.
@Malvoz good catch, see PR #55
*, ::before, ::after { animation-delay: -1s !important; animation-duration: 1s !important; ... }
As I understand it, the negative animation-delay
is used to break even with the animation-duration
of 1s
, however there's a bug in Safari where negative animation-delay is treated as 0s
, resulting in (I assume) an effective animation-duration
of 1s
and not 0s
- just an FYI. If we have to choose which bug to avoid, I guess it's still better to have a potential 1s
animation-delay than setting animation-delay
(and animation-duration
) to 0s
which would break stuff using transitionEnd
or animationEnd
events in Safari (as suggested in https://github.com/mozdevs/cssremedy/issues/11#issuecomment-462527813).
Also I noticed there's no transition-delay: 0s !important
, I don't think that's intentional... is it?
@Malvoz
If you have to choose the lesser of two evils; you can make a significantly less evil, lesser evil:
*, ::before, ::after {
animation-delay: -1ms !important;
animation-duration: 1ms !important;
...
}
That should still produce a net 0s
duration except for bugged Safari, where a 1ms
duration is still far more acceptable than a 1s
duration.
@rjgotten I agree.
@mirisuzanne do you mind checking out https://github.com/mozdevs/cssremedy/issues/11#issuecomment-557808192, and https://github.com/mozdevs/cssremedy/issues/11#issuecomment-557944270? Thanks!
@Malvoz That all makes sense to me. Do you want to open a PR?
This has already been included in the PR above, but for those looking at this thread, make sure to also zero out the transition delay.
I wrote
Or I should say, I snagged that code from discussions on Twitter. Which I'd linked to, but then erased the link. Hm, I should find it again.
@meyerweb raised a good point — why 0.1s and not 0?
Also, do browsers not do this already? Is there no mandate in the CSS spec for user agents to enforce this? Why not? Or if there is (and browsers just haven't implemented it yet), then what is it? What was the discussion about this?
Likely there's some back story with wisdom we can draw from.