Parallax backgrounds and scroll-linked transforms trigger vection illusions that activate motion-sickness pathways in users with vestibular disorders
2.3.3 Animation from Interactions
In Plain Language
[2.3.3 Animation from Interactions, Level AAA, new in WCAG 2.1[1]] requires that motion animation triggered by a user interaction -- parallax scrolling, slide-in transitions, page-flip effects, scroll-jacking -- can be disabled, unless the animation is essential to the functionality or information being conveyed.
The scope is user-triggered motion specifically. Animations that start on their own and keep running fall under 2.2.2 Pause, Stop, Hide[2]; 2.2.2 is about user-controlled pause of auto-playing motion, while 2.3.3 is about letting users opt out of motion that fires in response to scroll, click, or hover.
Why It Matters
- Users with vestibular disorders -- benign paroxysmal positional vertigo (BPPV), vestibular migraine, Meniere's disease -- experience nausea, dizziness, and disorientation from large-scale motion on screen. The W3C Understanding document notes the reaction can be severe enough to require bed rest to recover[1].
- Parallax scrolling is the most common trigger. The difference in velocity between foreground and background layers produces a vection illusion -- the visual system interprets the moving field as self-motion, activating the same neural pathways as physical motion sickness.
- The "essential" exception is narrow. An animation is essential when removing it would change the information or break the function: a drag preview that follows the pointer, a progress indicator that shows work happening, the animation preview in an animation tool. Decorative slide-ins, scroll-linked zooms, and parallax backgrounds do not qualify.
- When motion cannot be disabled, affected users close the tab. The cost of the decorative flourish is the loss of the entire page.
Examples
Scroll-triggered fade-in with reduced-motion override:
@media (prefers-reduced-motion: reduce) {
.reveal { animation: none; opacity: 1; }
}
✔ Users who enable reduced motion see content immediately without animation
<style>
.reveal {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
/* Disable motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
.reveal {
animation: none;
transition: none;
opacity: 1;
transform: none;
}
}
</style>
<div class="reveal">
Content fades in on scroll -- or appears
instantly when reduced motion is enabled.
</div>
Settings panel with animation toggle:
<label>
<input type='checkbox' id='reduce-motion'>
Reduce motion
</label>
✔ Users can disable interaction-triggered animations directly in the site
<!-- Site-level toggle for users without OS-level setting -->
<label class="motion-toggle">
<input type="checkbox" id="reduce-motion">
Reduce motion
</label>
<script>
const checkbox = document.getElementById('reduce-motion');
checkbox.addEventListener('change', () => {
document.documentElement.classList.toggle(
'no-motion', checkbox.checked
);
});
</script>
<style>
.no-motion *,
.no-motion *::before,
.no-motion *::after {
animation-duration: 0s !important;
transition-duration: 0s !important;
}
</style>
Parallax background that moves as the user scrolls:
background-attachment: fixed;
/* No reduced-motion override */
✘ Parallax motion is triggered by scrolling and cannot be disabled -- fails 2.3.3
Cards that zoom and rotate on hover:
.card:hover { transform: scale(1.1) rotate(2deg); }
/* No prefers-reduced-motion check */
✘ Hover-triggered motion animation with no way to turn it off fails 2.3.3
How to Fix It
- Gate motion on
prefers-reduced-motion. The CSS media queryprefers-reduced-motion: reducereflects the OS-level setting (macOS: System Settings > Accessibility > Display > Reduce motion; Windows 11: Settings > Accessibility > Visual effects > Animation effects; iOS/Android have equivalents). Default to no motion and opt in with@media (prefers-reduced-motion: no-preference) { ... }, or default to motion and override inside@media (prefers-reduced-motion: reduce) { ... }. Either pattern satisfies 2.3.3 as long as the reduced-motion branch actually stops the transform. - Provide an in-page toggle too. Users on shared machines, kiosks, or locked-down corporate builds cannot always set the OS preference. A visible "reduce motion" control that toggles a class on
<html>gives them a direct override. - Audit scroll-linked transforms. Parallax backgrounds (
background-attachment: fixedwith layered movement), scroll-driventransform: translate3d(),IntersectionObserver-triggered slide-ins, and the CSSscroll-timeline/animation-timeline: scroll()APIs all produce interaction-triggered motion. Each one needs a reduced-motion branch. - Replace motion, do not just slow it. Setting
transition-duration: 0soranimation: noneand jumping to the end state is the correct behaviour. Slowing an animation from 600ms to 200ms still produces vection. - Preserve essential animation. A pointer-following drag preview, a progress spinner that indicates in-flight work, or the playback view of an animation editor are essential under 2.3.3 and stay on. The test is whether removing the motion destroys the information or the function -- if the user can still understand and operate the page without it, it is decorative and must be disableable.
References
- [1] W3C (2023). Understanding Success Criterion 2.3.3: Animation from Interactions. W3C, Accessed 2026-04-07. https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html ↩ ↩
- [2] W3C (2023). Understanding Success Criterion 2.2.2: Pause, Stop, Hide. W3C, Accessed 2026-04-07. https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html ↩