require-reduced-motion-override-for-interactive-transitions
Require a @media (prefers-reduced-motion) override when interactive selectors declare transition or animation.
Targeted pattern scopeโ
This rule targets transition, transition-property, transition-duration, animation, animation-name, and animation-duration declarations on CSS rule selectors that contain interactive pseudo-classes: :hover, :focus, :focus-visible, :focus-within, and :active.
The rule skips declarations whose value is already a safe no-motion value (none, 0s, initial, unset, inherit, revert, or a zero-duration shorthand such as 0ms).
The rule also skips declarations that are already written inside a @media (prefers-reduced-motion) block โ those are already part of the reduced-motion handling path.
What this rule reportsโ
The rule reports transition or animation declarations on interactive selectors when no @media (prefers-reduced-motion: reduce) companion exists in the file that covers the same selector.
"Covered" means one of the following is true:
- A
@media (prefers-reduced-motion)block in the file contains a rule with the same selector. - A
@media (prefers-reduced-motion)block in the file contains a rule with the base selector (the interactive pseudo-classes stripped from the selector โ for example.buttonas the base of.button:hover). - A
@media (prefers-reduced-motion)block in the file contains a universal-selector reset (*,*::before, or*::after) that setstransitionoranimationto a safe value such asnone.
Why this rule existsโ
Users who prefer reduced motion (WCAG 2.1 Success Criterion 2.3.3, AAA) or who have configured their operating system to minimise motion may not see the elegant CSS transitions you designed โ they may instead experience nausea, vestibular disorder symptoms, or discomfort.
Docusaurus sites commonly add hover and focus transitions to navbar links, sidebar items, buttons, and interactive cards. Each of those transitions should have a paired @media (prefers-reduced-motion: reduce) block that suppresses or greatly reduces the motion.
This rule surfaces missing companions before users are affected.
โ Incorrectโ
/* Missing @media (prefers-reduced-motion) companion */
.navbar__link:hover {
color: var(--ifm-color-primary);
transition: color 0.2s ease;
}
/* Missing companion even though another reduced-motion block exists for a different selector */
.sidebar__link:focus-visible {
outline-offset: 2px;
transition: outline-offset 0.15s ease;
}
@media (prefers-reduced-motion: reduce) {
.hero__cta:hover {
transition: none;
}
}
โ Correctโ
/* Exact selector companion */
.navbar__link:hover {
color: var(--ifm-color-primary);
transition: color 0.2s ease;
}
@media (prefers-reduced-motion: reduce) {
.navbar__link:hover {
transition: none;
}
}
/* Base selector companion (without interactive pseudo) */
.sidebar__link:focus-visible {
outline-offset: 4px;
transition: outline-offset 0.15s ease;
}
@media (prefers-reduced-motion: reduce) {
.sidebar__link {
transition: none;
}
}
/* Universal reset companion โ covers all interactive selectors in the file */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation: none !important;
transition: none !important;
}
}
.button:hover {
transform: translateY(-2px);
transition: transform 0.2s ease;
}
.card:focus-visible {
box-shadow: 0 0 0 3px var(--ifm-color-primary);
transition: box-shadow 0.15s ease;
}
/* Already inside @media (prefers-reduced-motion: no-preference) โ safe */
@media (prefers-reduced-motion: no-preference) {
.hero__cta:hover {
transform: scale(1.04);
transition: transform 0.2s ease;
}
}
Behavior and migration notesโ
- Motion properties checked:
transition,transition-property,transition-duration,animation,animation-name,animation-duration. - Interactive pseudo-classes checked:
:hover,:focus,:focus-visible,:focus-within,:active. - Companion discovery: The rule scans the entire file for
@media (prefers-reduced-motion)blocks; the companion does not need to be adjacent to the flagged declaration. - No autofix is provided. Safe motion suppression depends on design intent and it is impossible to automatically determine whether
transition: noneor a reduced alternative (e.g.transition: opacity 0.05s) is the correct replacement. recommended: falseโ this rule is opt-in. Enable it when you want strict reduced-motion hygiene across your Docusaurus CSS.
Additional examplesโ
โ
Correct โ safe none value requires no companionโ
/* transition: none is already a no-motion value, nothing to flag */
.navbar__link:hover {
transition: none;
}
โ Correct โ reduced-motion block uses the unqualified base selectorโ
.menu__link:active {
background: var(--ifm-color-primary-lightest);
transition: background 0.1s ease;
}
@media (prefers-reduced-motion: reduce) {
/* Covers .menu__link:active via base selector match */
.menu__link {
transition: none;
}
}
โ Incorrect โ companion exists but does not cover this selectorโ
.badge:hover {
transform: scale(1.08);
transition: transform 0.2s ease;
}
@media (prefers-reduced-motion: reduce) {
/* Covers .card:hover, not .badge:hover */
.card:hover {
transition: none;
}
}
Stylelint config exampleโ
import { docusaurusPluginConfigs } from "stylelint-plugin-docusaurus";
export default {
...docusaurusPluginConfigs["docusaurus-all"],
rules: {
...docusaurusPluginConfigs["docusaurus-all"].rules,
"docusaurus/require-reduced-motion-override-for-interactive-transitions": true,
},
};
When not to use itโ
Disable this rule if your site already enforces reduced-motion compliance through a global reset stylesheet or a third-party accessibility utility that handles prefers-reduced-motion at a different layer. You can also disable it for individual declarations using a /* stylelint-disable-next-line */ comment when the transition is intentionally safe (for example a short opacity fade that is not considered vestibular-triggering).
Package documentationโ
Docusaurus package documentation:
Further readingโ
- MDN: prefers-reduced-motion
- WCAG 2.1 SC 2.3.3 Animation from Interactions (AAA)
- WebAIM: Vestibular Disorders and Motion Sensitivity
- CSS Tricks: An Introduction to the Reduced Motion Media Query
Rule catalog ID: R027