Skip to content

Reduced motion: honor prefers-reduced-motion for video + logo, add hero pause control (#1294)#1353

Merged
jonfroehlich merged 1 commit into
masterfrom
1294-reduced-motion-video-logo-pause
Jun 19, 2026
Merged

Reduced motion: honor prefers-reduced-motion for video + logo, add hero pause control (#1294)#1353
jonfroehlich merged 1 commit into
masterfrom
1294-reduced-motion-video-logo-pause

Conversation

@jonfroehlich

@jonfroehlich jonfroehlich commented Jun 19, 2026

Copy link
Copy Markdown
Member

Closes #1294.

Makes the three remaining motion sources honor the OS-level prefers-reduced-motion preference, and adds a WCAG 2.2.2 (Pause, Stop, Hide, Level A) pause mechanism for the auto-moving hero. No in-page motion toggle (that was rejected in #1196).

Approach — progressive enhancement

CSS can't stop <video> playback or a <canvas> loop, so JS is genuinely required for those. Guiding principle: the no-JS HTML baseline delivers the content; JS only removes motion for people who asked for less.

  • The hero <video> keeps autoplay muted loop — JS-disabled users get the video exactly as today (no regression). JS pauses it under reduced motion / via the pause control; it never enables it.
  • Rejected the <source media="(prefers-reduced-motion: no-preference)"> trick — Chrome/Safari dropped media on <video>/<source> (Firefox-only now).

Three surfaces tied together by one shared helper and one pause control.

Changes

  • js/reduced-motion.js (new): shared window.MakeLab.prefersReducedMotion(), queried live (an OS toggle mid-session is respected without reload). Loaded before carousel.js; the makelab-logo.js module reads it too.
  • Hero video (base.html + carousel.js): keep autoplay; add a poster from the banner's existing image when set (no model change); carousel.js pauses the active video under reduced motion so the poster shows.
  • Logo canvas (makelab-logo.js): under reduced motion, pin the morph to its assembled end state (lerp = 1), skip the scroll handler (keep ResizeObserver for sizing), and drop "Animated" from the canvas label.
  • WCAG 2.2.2 (base.html + carousel_fade.css + carousel.js): one visible, keyboard-operable Pause/Play toggle governing both the auto-advance and the looping video. Real <button>, dynamic aria-label/icon, ≥44×44 target, contrast chip, focus ring. Ships hidden so no-JS users never see a dead control; carousel.js reveals it only when motion exists.

Testing

  • New regression tests (test_hero_motion.py): hero video keeps autoplay, gets a poster only when the banner has an image, and the pause control renders. 4/4 pass.
  • Full suite: 412 pass / 8 skipped, no regressions.
  • Pa11y: neither the pause button nor the video appears in the output → no new violations (the failing baseline is the site's pre-existing color-contrast debt, unrelated).
  • Manual: verified on macOS toggling Reduce motion on/off in Accessibility settings — video, logo, and carousel all respond live; pause button keyboard-operable.

Screenshots

image

Refs #1196, #1288, #1293.

🤖 Generated with Claude Code

…ause control (#1294)

Three motion sources now respect the OS-level prefers-reduced-motion
preference, plus a WCAG 2.2.2 (Pause, Stop, Hide) pause mechanism for the
auto-moving hero.

- New shared helper window.MakeLab.prefersReducedMotion() (reduced-motion.js),
  queried live so an OS toggle mid-session is respected; loaded before
  carousel.js and consulted by the makelab-logo.js module too.
- Hero video: keep autoplay in the markup (progressive enhancement — the
  no-JS baseline still plays); carousel.js pauses the active video under
  reduced motion / the pause control so the poster shows. Poster comes from
  the banner's existing image when set (no model change).
- Logo canvas: under reduced motion, pin the morph to its assembled end state
  (lerp = 1), skip the scroll handler, and drop "Animated" from the label.
- WCAG 2.2.2: one visible, keyboard-operable pause/play toggle governing both
  the auto-advance and the looping video. Ships hidden so no-JS users never
  see a dead control; carousel.js reveals it only when motion exists.
- Regression tests: hero video keeps autoplay, gets a poster only when the
  banner has an image, and the pause control renders.

Refs #1196, #1288, #1293.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jonfroehlich jonfroehlich merged commit f87c5a2 into master Jun 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduced motion: video + logo canvas should honor prefers-reduced-motion; add WCAG 2.2.2 pause for hero video

1 participant