Accessible Animations
Animation can genuinely improve an interface — drawing attention to a change, showing spatial relationships, easing a transition between states. It can also actively harm some users if it isn't built with a few accessibility considerations in mind. This page builds on prefers-reduced-motion and covers what else responsible motion design needs to account for.
Recap: prefers-reduced-motion
The starting point for any non-trivial animation is respecting the prefers-reduced-motion media query, which reflects a system-level setting some users enable because motion causes them dizziness, nausea, or triggers vestibular disorders. See prefers-reduced-motion for the full details — the short version:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}Flashing content and seizure risk
Beyond motion sensitivity, rapidly flashing content is a genuine WCAG requirement, not a stylistic preference — certain flash patterns can trigger seizures in users with photosensitive epilepsy. WCAG's general guidance is to avoid content that flashes more than three times per second, and to avoid large-area flashes combining red with other saturated colors, unless the flash is below the guideline's size and contrast thresholds.
Animations that interfere with reading or focus
A few less obvious considerations round out accessible motion design:
Avoid animating text a user is expected to read while it's moving — scrolling marquees or bouncing headlines make reading measurably harder for users with cognitive or attention-related disabilities, and are mildly annoying for everyone else.
Don't let an animation trap keyboard focus — if a modal or carousel animates in, focus should move to it (or stay put) predictably, not get lost mid-transition or land somewhere unexpected.
Time screen-reader announcements around animation, not against it — if content animates in and an ARIA live region announces it immediately, make sure the announcement isn't cut off or delayed in a confusing way by the transition itself.
Provide pause/stop controls for any animation that repeats indefinitely and lasts more than a few seconds — auto-playing carousels and looping background video are common offenders.
Worked example: decorative animation with a fallback
/* A subtle looping "shimmer" on a loading skeleton — purely decorative,
conveys no information beyond "content is loading" */
.skeleton {
background: linear-gradient(
90deg,
#eee 25%,
#f5f5f5 37%,
#eee 63%
);
background-size: 400% 100%;
animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer {
0% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Reduced-motion fallback: keep the loading indication (the gray
block itself is still visible and communicates "loading") but drop
the moving animation entirely rather than slowing it down */
@media (prefers-reduced-motion: reduce) {
.skeleton {
animation: none;
background: #eee;
}
}