skip to content

In CSS, where does the prefers-reduced-motion media feature get its value from, what are its two possible values, and what does the bare query @media (prefers-reduced-motion) match?

level: juniorimportance: should knowfreq 45%

answer

  1. the browser reads it, cannot write it
  2. an operating-system accessibility switch
  3. exactly two values, no third
  4. boolean form has a false-equivalent value
  5. it changes live, no reload needed

basics

~20 s

The browser reads an operating-system accessibility setting and exposes it to CSS as one of two values: reduce when the user asked for less motion, and no-preference otherwise. The bare query without a value matches only reduce, because no-preference evaluates as false in boolean context.

solid answer

~40 s

`prefers-reduced-motion` is a user-preference media feature. Its value comes from the operating system — "Reduce motion" on macOS and iOS, the animation-effects switch on Windows, "Remove animations" on Android — and the page can read it but never set it. It has exactly two values: `reduce`, meaning the user has asked for less non-essential motion, and `no-preference`, the default when that switch is off. Written in boolean form as `@media (prefers-reduced-motion)`, it matches only when the value is `reduce`, because `no-preference` is defined to evaluate as false in boolean context — a nice shorthand for the common case. Since the value tracks a live system setting, it can change while the page is open, and the matching rules re-evaluate immediately.

go deeper

for a junior

Be able to name both values, say the value comes from an operating-system accessibility setting, and write the query correctly on the first try without inventing a keyword.

for a middle

Explain boolean context — why the bare query equals the reduce form — and that the value is live, so matching updates without a reload while the page is open.

for a senior

Point out that honouring the preference is almost entirely the author's responsibility, and that an unknown feature fails to match in either direction, which decides how gated styles degrade.

for a principal

Frame it as one of a family of user-preference signals the product must respect consistently, and decide how a product-level motion setting relates to the system one rather than competing with it.

## What kind of feature this is Most media features describe the output device: `width`, `resolution`, `orientation`. `prefers-reduced-motion` belongs to a different family, the user-preference features, alongside things like `prefers-color-scheme` and `prefers-contrast`. These describe the *person*, or more precisely the settings the person has configured in their environment, surfaced to CSS so a page can adapt without asking. The practical consequence is that the value does not come from your page and cannot be set by it. There is no CSS property, no meta tag, and no script API that writes it — a page that wants an in-app motion toggle has to build its own signal alongside this one. ## Where the value comes from The browser maps a platform accessibility setting onto the feature: - macOS: System Settings → Accessibility → Display → Reduce motion - iOS / iPadOS: Settings → Accessibility → Motion → Reduce Motion - Windows: Settings → Accessibility → Visual effects → Animation effects (off) - Android: Settings → Accessibility → Remove animations - GNOME: the animations setting in the desktop's accessibility options No browser prompts for this, and very few users find it by accident — which is exactly why the ones who set it mean it. ## The two values The feature has precisely two values, and knowing there is no third is a common check: - `reduce` — the user has indicated they prefer an interface that minimises non-essential motion. - `no-preference` — the user has expressed no such preference. This is the value when the setting is off; it does not mean "the user wants motion", it means the browser has nothing to report. There is no `none`, no `less`, no numeric level. Writing `@media (prefers-reduced-motion: none)` matches nothing, and because CSS discards rules it cannot parse, the block is silently skipped — a typo that looks like working code. ```css /* matches only when the user asked for reduced motion */ @media (prefers-reduced-motion: reduce) { } /* matches only when they did not */ @media (prefers-reduced-motion: no-preference) { } ``` ## The boolean shorthand Media features can be written without a value, in what the specification calls boolean context, and then they match when the feature's value is not the false-equivalent one. For `prefers-reduced-motion` the specification defines `no-preference` as evaluating to false, so: ```css @media (prefers-reduced-motion) { /* equivalent to (prefers-reduced-motion: reduce) */ } ``` This reads nicely — "if the user prefers reduced motion" — and is exactly equivalent to the explicit `reduce` form. Be aware that the analogous shorthand does not carry the same meaning for every preference feature, so learn each one rather than generalising. ## What happens where the feature is unknown If an engine does not implement the feature, the query does not match, and negating it does not help either: an unknown feature makes the whole query fail rather than flipping to true. So on such a browser, `(prefers-reduced-motion: reduce)` does not match, and neither does `(prefers-reduced-motion: no-preference)`. Every current major engine implements it, but this rule explains why styles gated on `no-preference` disappear entirely on very old browsers rather than falling back to "animate". ## It is live The value tracks the system setting while the page is open. If someone turns Reduce Motion on mid-session, matching re-evaluates and the styles in the newly matching block apply immediately — you do not need a reload. That also makes testing easy: keep the accessibility panel open next to the browser and toggle it while watching the page. ## Common mistakes at this level The first is assuming `no-preference` means the user asked for animation; it only means nothing was reported, and it is the value the overwhelming majority of visitors have. The second is expecting the browser to act on the preference for you — with a small number of exceptions, honouring it is entirely the author's job, and an unhandled page animates exactly the same for everyone. The third is inventing a value; `reduce` and `no-preference` are the complete set.

  • Does the browser automatically shorten animations when the preference is set?
    No, with narrow exceptions. Honouring the preference in your own animations and transitions is the author's job: an unhandled page animates identically for everyone. That is why the media query exists at all — the browser reports the preference and leaves the response to CSS.
  • Can a page set prefers-reduced-motion for the user, for instance from a settings screen?
    No. It is a read-only reflection of an environment setting; CSS has no property that writes it and there is no browser API to override it. An in-app motion toggle has to be a separate signal your own styles consult — typically an attribute or class on the root element — used alongside the media query, not instead of it.
  • What does @media (prefers-reduced-motion: none) match?
    Nothing. The only valid values are reduce and no-preference, so that query is invalid and the browser drops the block. It is a dangerous typo because it looks plausible and fails silently — your reduced-motion styles simply never apply, with no console error to point at.

saying these in an interview costs you the question

  • Thinks no-preference means the user wants animation
  • Assumes the browser disables animations automatically when it is set
  • Invents extra values such as none or less
  • Believes a page can set the preference for the user
  • Thinks the page must reload after the OS setting changes

context