A set of client hint headers allows sites to obtain the user's media preferences optionally at request time, allowing servers to inline the right CSS for performance reasons.
CSS media queries, and specifically
user preference media features like
prefers-color-scheme
or
prefers-reduced-motion
, have a potentially
significant impact
on the amount of CSS that needs to be delivered by a page, and on the experience the user is going
to have when the page loads.
Focusing on prefers-color-scheme
—but highlighting that the reasoning applies to other user
preference media features as well—it is a best practice to not load CSS for the particular
non-matching color scheme in the critical rendering path, and instead to initially only load the
currently relevant CSS. One way of doing so is
via <link media>
.
However, high-traffic sites like Google Search that wish to honor user
preference media features like prefers-color-scheme
and that inline CSS for performance reasons,
need to know about the preferred color scheme (or other user preference media features respectively)
ideally at request time, so that the initial HTML payload already has the right CSS inlined.
Additionally, and specifically for prefers-color-scheme
, sites by all means want to avoid a
flash of inaccurate color theme.
The Sec-CH-Prefers-Color-Scheme
and the Sec-CH-Prefers-Reduced-Motion
client hint headers are the first of a
series of user preference media features client hints headers
that aims to solve this issue.
Background on client hints
HTTP Client Hints defines an Accept-CH
response
header that servers can use to advertise their use of request headers for proactive content
negotiation, colloquially referred to as client hints. The
User Preference Media Features Client Hints Headers
proposal defines a set of client hints aimed at conveying user preference media features. These
client hints are named after the corresponding user preference media feature that they report on.
For example, the currently preferred color scheme as per prefers-color-scheme
is reported via the
aptly named Sec-CH-Prefers-Color-Scheme
client hint.
Background on critical client hints
The client hints proposed in User Preference Media Features Client Hints Headers will presumably most commonly be used as Critical Client Hints. Critical Client Hints are Client Hints which meaningfully change the resulting resource. Such a resource should be fetched consistently across page loads (including the initial page load) to avoid jarring user-visible switches.
Client hint syntax
User preference media features consist of a name (like prefers-reduced-motion
) and allowed values
(like no-preference
or reduce
). Each client hint header field is represented as
Structured Headers for HTTP
object containing an
item whose value
is a string. For
example, to convey that the user prefers a dark theme and reduced motion, the client hints look like
in the example below.
GET / HTTP/2
Host: example.com
Sec-CH-Prefers-Color-Scheme: "dark"
Sec-CH-Prefers-Reduced-Motion: "reduce"
The CSS equivalent of the information conveyed in the above client hints is
@media (prefers-color-scheme: dark) {}
and @media (prefers-reduced-motion: reduce) {}
respectively.
Complete list of the client hints
The list of the client hints is modeled after the user preference media features in Media Queries Level 5.
Client Hint | Allowed Values | Corresponding User Preference Media Feature |
---|---|---|
Sec-CH-Prefers-Reduced-Motion |
no-preference , reduce |
prefers-reduced-motion |
Sec-CH-Prefers-Reduced-Transparency |
no-preference , reduce |
prefers-reduced-transparency |
Sec-CH-Prefers-Contrast |
no-preference , less , more , custom |
prefers-contrast |
Sec-CH-Forced-Colors |
active , none |
forced-colors |
Sec-CH-Prefers-Color-Scheme |
light , dark |
prefers-color-scheme |
Sec-CH-Prefers-Reduced-Data |
no-preference , reduce |
prefers-reduced-data |
Browser support
The Sec-CH-Prefers-Color-Scheme
client hint header is supported on Chromium 93.
The Sec-CH-Prefers-Reduced-Motion
client hint header is supported on Chromium 108.
Other vendors' feedback, namely WebKit's
and Mozilla's, is pending.
Demo of Sec-CH-Prefers-Color-Scheme
Try the demo in Chromium 93 and notice how the inlined CSS changes according to the user's preferred color scheme.
Demo of Sec-CH-Prefers-Reduced-Motion
Try the demo in Chromium 108 and notice how the inlined CSS changes according to the user's motion preferences.
How it works
- The client makes an initial request to the server.
bash GET / HTTP/2 Host: example.com
- The server responds, telling the client via
Accept-CH
that it accepts theSec-CH-Prefers-Color-Scheme
and theSec-CH-Prefers-Contrast
Client Hints, out of which as perCritical-CH
it considersSec-CH-Prefers-Color-Scheme
a Critical Client Hint that it also varies the response on as conveyed byVary
.bash HTTP/2 200 OK Content-Type: text/html Accept-CH: Sec-CH-Prefers-Color-Scheme, Sec-CH-Prefers-Contrast Vary: Sec-CH-Prefers-Color-Scheme Critical-CH: Sec-CH-Prefers-Color-Scheme
- The client then retries the request, telling the server via
Sec-CH-Prefers-Color-Scheme
that it has a user preference for dark-schemed content.bash GET / HTTP/2 Host: example.com Sec-CH-Prefers-Color-Scheme: "dark"
- The server can then tailor the response to the client's preferences accordingly and, for example, inline the CSS responsible for the dark theme into the response body.
Node.js example
The Node.js example below, written for the popular Express.js framework, shows how
dealing with the Sec-CH-Prefers-Color-Scheme
client hint header could look like in practice.
This code is what actually powers the demo above.
app.get("/", (req, res) => {
// Tell the client the server accepts the `Sec-CH-Prefers-Color-Scheme` client hint…
res.set("Accept-CH", "Sec-CH-Prefers-Color-Scheme");
// …and that the server's response will vary based on its value…
res.set("Vary", "Sec-CH-Prefers-Color-Scheme");
// …and that the server considers this client hint a _critical_ client hint.
res.set("Critical-CH", "Sec-CH-Prefers-Color-Scheme");
// Read the user's preferred color scheme from the headers…
const prefersColorScheme = req.get("sec-ch-prefers-color-scheme");
// …and send the adequate HTML response with the right CSS inlined.
res.send(getHTML(prefersColorScheme));
});
Privacy and security considerations
The Chromium team designed and implemented User Preference Media Features Client Hints Headers using the core principles defined in Controlling Access to Powerful Web Platform Features, including user control, transparency, and ergonomics.
The Security Considerations of HTTP Client Hints and the Security Considerations of Client Hint Reliability likewise apply to this proposal.
References
- Spec draft
- Explainer
- Sec-CH-Prefers-Color-Scheme - Chrome Status entry
- Sec-CH-Prefers-Color-Scheme - Chromium bug
- Sec-CH-Prefers-Reduced-Motion - Chrome Status entry
- Sec-CH-Prefers-Reduced-Motion - Chromium bug
- WebKit thread
- Mozilla Standards Position
- Client Hints
- Client Hint Reliability
- Media Queries Level 5
- Structured Headers for HTTP
Acknowledgements
Many thanks for valuable feedback and advice from Yoav Weiss. Hero image by Tdadamemd on Wikimedia Commons.