hints / preference
Sec-CH-Prefers-Reduced-Motion
Sec-CH-Prefers-Reduced-Motion carries the user’s reduced-motion accessibility setting to the server, enabling motion-free server-rendered pages from the first byte.
- Example
Sec-CH-Prefers-Reduced-Motion: reduce- JavaScript
matchMedia('(prefers-reduced-motion: reduce)')- Available since
- Chrome 108 (2022)
- Engines
- Chrome Edge Opera Firefox Safari
- References
- MDN · Specification
Sec-CH-Prefers-Reduced-Motion is the request-header form of the prefers-reduced-motion media query, the accessibility setting people enable when animation causes them discomfort, from vestibular disorders to plain distaste for parallax.
Accept-CH: Sec-CH-Prefers-Reduced-Motion
Sec-CH-Prefers-Reduced-Motion: reduce # user asked for calm
Sec-CH-Prefers-Reduced-Motion: no-preference # default The value is an unquoted token: no-preference or reduce.
When the header beats the media query
Pure CSS animation is already handled by @media (prefers-reduced-motion: reduce); you don’t need a server for that. The header earns its place when motion is decided server-side:
- Choosing between a video hero and a static image in the HTML itself.
- Skipping the autoplaying carousel markup entirely, rather than pausing it after hydration.
- Not shipping the 80 KB animation library to someone who asked for stillness, a performance win disguised as an accessibility feature.
As with all preference hints, add Vary: Sec-CH-Prefers-Reduced-Motion when the response depends on it, and consider Critical-CH if the un-hinted first response would be jarring (details on the Accept-CH page).
In JavaScript
const calm = matchMedia('(prefers-reduced-motion: reduce)').matches; Works everywhere; only the header is Chromium-only. This very site uses the media-query form: the capture panel’s typing animation collapses to an instant render under reduce.
Respect what it means
reduce is not “no animation ever”; it means unnecessary motion should go. A subtle opacity fade is fine. A full-viewport zoom-parallax scroll is not. The header just gets that decision to your server one round-trip earlier.