Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rule to enforce use of prefers-reduced-motion with animations and transitions #6202

Open
mattxwang opened this issue Jul 13, 2022 · 6 comments
Labels
status: needs discussion triage needs further discussion

Comments

@mattxwang
Copy link
Member

mattxwang commented Jul 13, 2022

What is the problem you're trying to solve?

Branching off of our discussion around accessibility features in @stylelint/contributors and a discussion with the FE accessibility team at @chanzuckerberg, one pattern we want to enforce is the use of prefers-reduced-motion in blocks that also define animations and transitions.

One positive use-case, taken from @chanzuckerberg's design system

.loading-indicator__icon {
  animation: rotateIcon 2s linear infinite;

  @media screen and (prefers-reduced-motion) {
    animation: none;
  }
}

In contrast, we would like to disallow

.loading-indicator__icon {
  animation: rotateIcon 2s linear infinite;
  /* error: prefers-reduced-motion is not used here */
}

A similar rule could apply to transition-* keywords as well; CZI's design system has a use-case for that as well.

Two caveats:

  1. I am not sure if this is within scope of core Stylelint. If this is better suited for stylelint-accessible or somewhere else (e.g. another custom plugin), please let me know!
  2. I am not sure if this is technically feasible, not performant, or would trigger too many false positives/negatives.
    • In particular, @dierat has noted that this may not apply to other types of animations/transitions that don't involve movement.

What solution would you like to see?

A rule to enforce the behaviour explained above. I'm no naming expert, so help there is certainly welcome!

With the caveat that I have little experience writing rule specs, I'm thinking something like:

  • Name: animation-require-prefers-reduced-motion (name pending)
  • Primary option: none (would we want to add some sort of ignoreSelectors feature here?
  • Secondary options: none
  • Autofixable: No
  • Message: - Expected prefers-reduced-motionto be used within declaration block
  • Description: "Enforce the use of prefers-reduced-motion when defining animations and transitions."
  • Extended description: more polished text about the importance of prefers-reduced-motion and accessibility
  • Section: not sure - would we create a new subsection under Enforce conventions?

I'm happy to work on an implementation pending the discussion on this rule!

@mattxwang
Copy link
Member Author

cc: @thibaudcolas (is this what you meant by correct use of prefers-reduced-motion and @dierat for the rule suggestion within CZI.

@mattxwang mattxwang changed the title Add animation-require-prefers-reduced-motion (name pending) Add rule to enforce use of prefers-reduced-motion with animations and transitions Jul 13, 2022
@thibaudcolas
Copy link
Member

@mattxwang yup. See also stylelint-a11y’s rule.

Another common way to implement prefers-reduced-motion is to remove all animations everywhere at once:

@media (prefers-reduced-motion: reduce) {
  *, ::before, ::after {
    animation-delay: -1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    background-attachment: initial !important;
    scroll-behavior: auto !important;
    transition-duration: 0s !important;
    transition-delay: 0s !important;
  }
}

I don’t think this undermines the usefulness of the rule as you suggested it, but it’s worth keeping in mind – at least the appropriateness of the rule to different approaches would need to be documented.

We also need to be careful with our examples (as this is what people will refer to when trying to figure out what to make of an error):

  • You have @media screen and (prefers-reduced-motion), I would have expected @media (prefers-reduced-motion: reduce). Not sure which makes the most sense / what the differences are.
  • animation: none would break any JS code relying on animation events (hence why my example above makes animations "instantaneous" rather than removing them completely).

@nosilleg
Copy link
Contributor

nosilleg commented Jul 14, 2022

Having a reset on all animations is considered to be an anti-pattern by many. As such I wouldn't consider the existence of animation reset code to be a strong consideration for not doing this work.

Two of the main three browser companies indicate that reduce should only reduce animation, not eliminate it. The decision about what to reduce is on a case by case basis. In my codebases I want each animation to have a comment describing why it does/does not have a reduce version. If we don't have a rule to enforce the comments, then I guess the next best thing is the exceptions having an explicit ignore of the rule.

That leads into the "too many false positives" concern. I do not consider it a concern because every animation should be evaluated and documenting that evaluation with an ignore line indicating an assessment was made seems like a minimal effort.

Apple

Webkit's take on it can be found here: https://webkit.org/blog/7551/responsive-design-for-motion/

That document has a lot of good examples of the visuals that should be reduced. A couple relevant statements from the document are:

The perceptual utility of appropriate, functional motion can increase the understandability and —yes— accessibility of a user interface.

Even if your site uses motion in a purely decorative sense, only remove the animations you know to be vestibular triggers. Unless a specific animation is likely to cause a problem, removing it prematurely only succeeds in making your site unnecessarily boring.

Google

Google has mixed messaging at https://web.dev/prefers-reduced-motion/:

reduce Indicates that the user has set an operating system preference indicating that interfaces should minimize movement or animation, preferably to the point where all non-essential movement is removed.

Despite earlier in the document acknowledging the usability and accessibility uses of motion.

Animation is oftentimes used to provide feedback to the user, for example, to let them know that an action was received and is being processed.

Mozilla

MDN article indicated that reduce is only for vestibular issues at https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion

reduce Indicates that user has notified the system that they prefer an interface that removes or replaces the types of motion-based animation that trigger discomfort for those with vestibular motion disorders.

@ybiquitous ybiquitous added the status: needs discussion triage needs further discussion label Jul 15, 2022
@ybiquitous
Copy link
Member

Thanks for the exciting proposal. The idea of requiring the prefers-reduced-motion media feature sounds good to me, but it seems we clarify the purpose of the rule.

The "About rules" doc says that built-in rules "have a singular purpose", but what properties should the new rule be applied to?

  • animation
  • animation-* (e.g. animation-duration)
  • transition
  • transition-* (e.g. transition-duration)
  • ...and more?

Also, what name should be suitable for the new rule, according to the naming guideline?

@mattxwang
Copy link
Member Author

See also stylelint-a11y’s rule.

Ah, I think I should've done a bit more homework before making this issue. It does seem like it fulfills the requirements that I'm suggesting (or at least - mostly. I'm not sure if I like the autofix). This is maybe part of the broader discussion about bringing either that plugin and/or @thibaudcolas's work into the main repo/namespace. @thibaudcolas, did you want to write up that issue based on our conversation in the contributors team, or did you want me to?

The "About rules" doc says that built-in rules "have a singular purpose", but what properties should the new rule be applied to?

I personally think all of animation, transition, and animation-*/transition-* should all be within scope, similar to the stylelint-a11y rule.

Also, what name should be suitable for the new rule, according to the naming guideline?

Thanks for pointing that out. Looking at "No rules", I think our rule just disallows something, and so probably needs *-no-*. Is there a unified word that describes animations and transitions in the spec?

@nosilleg
Copy link
Contributor

If the rule is looking for the existence of prefers-reduced-motion then *-no-unreduced-motion might be reasonable.

If a11y is going to be a part of core then maybe a11y-no-unreduced-motion works?
Closer to implementation instead of intent would be media-no-unreduced-motion.

I haven't looked at how difficult it is to limit the errors to "motion" based styles, but limiting it to vestibular based triggers I'm guessing is impossible. As such there will always be false positives.

The stylelint-a11y autofix is definitely a "no animation" instead of "reduced motion" implementation. I don't think this rule should be autofixable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs discussion triage needs further discussion
Development

No branches or pull requests

4 participants