How `prefers-reduced-motion` Affects Animated Diagrams: Complete Implementation Guide
When
prefers-reduced-motion: reduceis active, animated diagrams render as fully-static, semantically-complete frames with all motion controls hidden and decorative animation elements removed.
The Diagram Design system implements robust accessibility support for users with motion sensitivity. Rather than simply slowing animations, it presents a complete alternative experience that preserves all informational content while eliminating potentially harmful motion. This aligns with CSS Working Group recommendations and Web Content Accessibility Guidelines (WCAG) 2.1 requirements for motion reduction.
What prefers-reduced-motion Controls in Diagrams
The Diagram Design skill treats prefers-reduced-motion as a strict rendering contract rather than a cosmetic preference. According to SKILL.md, the system guarantees: "under prefers-reduced-motion: reduce it shows the complete static frame and hides/disables playback controls"【/cache/repos/github.com/cathrynlavery/diagram-design/main/skills/diagram-design/SKILL.md#L547-L549】.
This contract covers five specific behaviors:
- Static initialization — Diagrams render immediately at the final completed state
- Control suppression — All playback UI is hidden and disabled via CSS
- Decorative removal — Non-essential animated elements are removed from the DOM
- State exposure — Machine-readable attributes signal reduced-motion mode
- Print parity — Exports always use the same static representation
CSS Implementation Details
The core logic lives in skills/diagram-design/references/animation.md, specifically within the @media (prefers-reduced-motion: reduce) block【/cache/repos/github.com/cathrynlavery/diagram-design/main/skills/diagram-design/references/animation.md#L68-L78】.
Force-Completing All Animations
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
[data-motion-item] { opacity: 1 !important; transform: none !important; }
[data-motion-decorative] { display: none !important; }
[data-motion-controls] { display: none !important; }
}
This CSS performs three critical functions:
- Zero-duration animations —
0.001msforces immediate completion without breaking animation event detection - Motion item revelation —
[data-motion-item]elements become fully visible with no transforms - Element suppression — Decorative and control elements are removed via
display:none
DOM Structure and Data Attributes
The HTML scaffold uses semantic attributes to distinguish motion-critical from motion-decorative content:
<div class="motion-root" data-motion-state="reduced">
<!-- SVG content with semantic items -->
<svg>
<g data-motion-item="node1">…</g>
<g data-motion-item="node2">…</g>
</svg>
<!-- Controls present in markup but hidden when reduced motion is active -->
<div data-motion-controls>
<button data-motion-action="play">Play</button>
<button data-motion-action="pause">Pause</button>
<button data-motion-action="next">Next</button>
<button data-motion-action="previous">Previous</button>
</div>
<!-- Accessible status for screen readers -->
<div role="status" aria-live="polite">
Playback unavailable (reduced-motion preference)
</div>
</div>
The data-motion-state="reduced" attribute on the root element provides a JavaScript hook and styling target. Screen readers receive immediate notification through the aria-live region announcing that playback is unavailable.
Accessibility Guarantees
Semantic Preservation
The <title> and <desc> elements within SVG diagrams describe the complete meaning regardless of motion state. As noted in README.md, screen readers announce the diagram correctly even when prefers-reduced-motion shows the static frame【/cache/repos/github.com/cathrynlavery/diagram-design/main/README.md#L42-L44】.
No Partial State Exposure
The architectural decision documented in docs/adr/0003-reveal-is-the-only-sanctioned-autoplay.md ensures that "without JavaScript, all modes collapse to the static frame under reduced-motion"【/cache/repos/github.com/cathrynlavery/diagram-design/main/docs/adr/0003-reveal-is-the-only-sanctioned-autoplay.md#L11-L14】. This prevents users from encountering incomplete or transitional diagram states.
Multi-Context Application
Print and Export
The same CSS rules triggering on prefers-reduced-motion: reduce also apply to @media print. This guarantees that PDF exports and rasterized outputs (PNG/SVG) contain the finalized static frame rather than capturing mid-animation states.
Verification Testing
Two Python scripts validate the implementation:
# Verify a specific diagram file
python3 scripts/verify-motion.py path/to/animated-diagram.html
# Run complete test suite
python3 scripts/test-verify-motion.py
These scripts confirm that prefers-reduced-motion correctly:
- Hides control interfaces
- Disables decorative animation elements
- Exposes the static final frame【/cache/repos/github.com/cathrynlavery/diagram-design/main/skills/diagram-design/references/animation.md#L95-L103】
Key Implementation Files
| File | Purpose |
|---|---|
skills/diagram-design/references/animation.md |
CSS rules implementing reduced-motion handling; lines 68-78 define the media query block |
SKILL.md |
Contract documentation specifying static-frame rendering and control hiding |
README.md |
User-facing documentation of screen-reader and reduced-motion behavior |
docs/adr/0003-reveal-is-the-only-sanctioned-autoplay.md |
Architectural decision record on JavaScript-free fallback behavior |
Summary
prefers-reduced-motion: reducetriggers immediate static-frame rendering with all motion controls hidden- CSS in
animation.mdforces zero-duration animations and reveals alldata-motion-itemelements at full opacity - Decorative elements marked
data-motion-decorativeare removed from the visual DOM - Screen readers receive complete semantic content via
title/descelements and live-region status announcements - Print exports inherit the same static representation through shared
@mediarules - Verification scripts provide automated testing of motion-reduction compliance
Frequently Asked Questions
What happens if JavaScript is disabled?
The diagram falls back to the static frame automatically. Per the architectural decision record, the reduced-motion preference and no-JavaScript scenarios converge to identical behavior: a fully-rendered, non-animated diagram.
Do users see any animation at all with prefers-reduced-motion?
No. The 0.001ms animation duration forces immediate completion, and the data-motion-item override ensures all elements appear in their final state. There is no perceptible motion.
How do assistive technologies know playback is unavailable?
A role="status" element with aria-live="polite" announces "Playback unavailable (reduced-motion preference)" when the diagram initializes. This supplements the complete title and desc content already present in the SVG.
Can authors override this behavior for specific diagrams?
The !important declarations in the CSS rules prevent override, maintaining consistent accessibility compliance. Authors should design diagrams where the static frame conveys complete meaning without requiring animation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →