# How `prefers-reduced-motion` Affects Animated Diagrams: Complete Implementation Guide

> Learn how prefers-reduced-motion transforms animated diagrams into static, accessible frames. Discover the complete implementation guide for your diagrams.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: how-to-guide
- Published: 2026-08-14

---

> **When `prefers-reduced-motion: reduce` is 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`](https://github.com/cathrynlavery/diagram-design/blob/main/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`](https://github.com/cathrynlavery/diagram-design/blob/main/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

```css
@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:

1. **Zero-duration animations** — `0.001ms` forces immediate completion without breaking animation event detection
2. **Motion item revelation** — `[data-motion-item]` elements become fully visible with no transforms
3. **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:

```html
<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`](https://github.com/cathrynlavery/diagram-design/blob/main/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`](https://github.com/cathrynlavery/diagram-design/blob/main/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:

```bash

# 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`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md)** | CSS rules implementing reduced-motion handling; lines 68-78 define the media query block |
| **[`SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/SKILL.md)** | Contract documentation specifying static-frame rendering and control hiding |
| **[`README.md`](https://github.com/cathrynlavery/diagram-design/blob/main/README.md)** | User-facing documentation of screen-reader and reduced-motion behavior |
| **[`docs/adr/0003-reveal-is-the-only-sanctioned-autoplay.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/adr/0003-reveal-is-the-only-sanctioned-autoplay.md)** | Architectural decision record on JavaScript-free fallback behavior |

## Summary

- **`prefers-reduced-motion: reduce`** triggers immediate static-frame rendering with all motion controls hidden
- **CSS in [`animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/animation.md)** forces zero-duration animations and reveals all `data-motion-item` elements at full opacity
- **Decorative elements** marked `data-motion-decorative` are removed from the visual DOM
- **Screen readers** receive complete semantic content via `title`/`desc` elements and live-region status announcements
- **Print exports** inherit the same static representation through shared `@media` rules
- **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.