通过一组客户端提示标头,网站可以在请求时有选择地获取用户的媒体偏好设置,这使得服务器出于性能方面的考虑,可以内嵌正确的 CSS。
CSS 媒体查询(特别是 prefers-color-scheme
或 prefers-reduced-motion
等用户偏好设置媒体功能)可能会对网页需要提供的 CSS 数量以及用户在网页加载时的体验产生重大影响。
着眼于 prefers-color-scheme
,但要强调该推理也适用于其他用户偏好的媒体功能,最佳做法是不针对关键渲染路径中特定不匹配的配色方案加载 CSS,而是在一开始仅加载当前相关的 CSS。一种方法是通过 <link media>
。
但是,对于像 Google 搜索这样的高流量网站,出于性能方面的考虑,想要尊重用户偏好的媒体功能(如 prefers-color-scheme
)和内嵌 CSS,它们需要在理想情况下在请求时间了解首选配色方案(或其他用户偏好的媒体功能),以便初始 HTML 载荷已经内嵌了正确的 CSS。
此外,尤其是对于 prefers-color-scheme
,网站会尽一切努力避免不准确的色彩主题闪烁。
Sec-CH-Prefers-Color-Scheme
和 Sec-CH-Prefers-Reduced-Motion
客户端提示标头是旨在解决此问题的一系列用户偏好设置媒体功能客户端提示标头中的第一个。
客户端提示的背景信息
HTTP 客户端提示定义了一个 Accept-CH
响应标头,服务器可以使用该标头通告他们使用请求标头来进行主动式内容协商(俗称客户端提示)。用户偏好设置媒体功能客户端提示标头提案定义了一组旨在传达用户偏好设置媒体功能的客户端提示。这些客户端提示以它们报告的相应用户偏好设置媒体功能命名。例如,根据 prefers-color-scheme
的当前首选配色方案通过适当命名的 Sec-CH-Prefers-Color-Scheme
客户端提示进行报告。
关键客户端提示的背景信息
用户偏好设置媒体功能客户端提示标头中建议的客户端提示很可能最常用作关键客户端提示。关键客户端提示是指能够有效更改所生成资源的客户端提示。此类资源应在网页加载(包括初始网页加载)期间以一致的方式提取,以免干扰用户可见的切换。initial
客户端提示语法
用户偏好设置媒体功能包括名称(例如 prefers-reduced-motion
)和允许的值(例如 no-preference
或 reduce
)。每个客户端提示标头字段表示为 HTTP Structured Headers 对象,该对象包含一个值为字符串的 item。例如,为了表明用户更喜欢深色主题和减少动作,客户端提示如以下示例所示。
GET / HTTP/2
Host: example.com
Sec-CH-Prefers-Color-Scheme: "dark"
Sec-CH-Prefers-Reduced-Motion: "reduce"
上述客户端提示中传达的信息的 CSS 等效项分别是 @media (prefers-color-scheme: dark) {}
和 @media (prefers-reduced-motion: reduce) {}
。
客户端提示的完整列表
客户端提示列表是根据媒体查询级别 5 中的用户偏好设置媒体功能建模的。
客户端提示 | 允许的值 | 对应的用户偏好设置媒体功能 |
---|---|---|
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 |
浏览器支持
Chromium 93 支持 Sec-CH-Prefers-Color-Scheme
客户端提示标头。Chromium 108 支持 Sec-CH-Prefers-Reduced-Motion
客户端提示标头。其他供应商(即 WebKit 和 Mozilla 的)的反馈正在等待处理。
Sec-CH-Prefers-Color-Scheme
的演示
试用 Chromium 93 中的演示,您会发现内嵌 CSS 如何根据用户的首选配色方案发生变化。
Sec-CH-Prefers-Reduced-Motion
的演示
试用 Chromium 108 中的演示,您会发现内嵌 CSS 如何根据用户的动作偏好设置发生变化。
运作方式
- 客户端向服务器发出初始请求。
bash GET / HTTP/2 Host: example.com
- 服务器进行响应,通过
Accept-CH
告知客户端它接受Sec-CH-Prefers-Color-Scheme
和Sec-CH-Prefers-Contrast
客户端提示。根据Critical-CH
,其中会将Sec-CH-Prefers-Color-Scheme
视为关键客户端提示,指示其也会改变Vary
所传递的响应。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
- 然后,客户端重试该请求,通过
Sec-CH-Prefers-Color-Scheme
告知服务器它用户对采用深色方案的内容有偏好。bash GET / HTTP/2 Host: example.com Sec-CH-Prefers-Color-Scheme: "dark"
- 然后,服务器可以相应地根据客户端偏好设置定制响应,例如,将负责深色主题的 CSS 内嵌到响应正文中。
Node.js 示例
以下 Node.js 示例是为流行的 Express.js 框架编写的,展示了在实践中处理 Sec-CH-Prefers-Color-Scheme
客户端提示标头时可能的样子。此代码是上述演示的实际驱动因素。
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));
});
隐私权和安全注意事项
Chromium 团队按照控制对强大 Web 平台功能的访问权限(包括用户控制、透明度和工效学设计)中定义的核心原则,设计和实现了用户偏好设置媒体功能客户端提示标头。
HTTP 客户端提示的安全注意事项和客户端提示可靠性的安全注意事项同样适用于此方案。
参考编号
- 规范草稿
- 说明
- Sec-CH-Prefers-Color-Scheme - Chrome 状态条目
- Sec-CH-Prefers-Color-Scheme - Chromium bug
- Sec-CH-Prefers-Reduced-Motion - Chrome 状态条目
- Sec-CH-Prefers-Reduced-Motion - Chromium 错误
- WebKit 线程
- Mozilla 标准职位
- 客户端提示
- 客户端提示可靠性
- 媒体查询级别 5
- 适用于 HTTP 的结构化标头
致谢
非常感谢您提供 Yoav Weiss 的宝贵反馈和建议。主打图片,由 Tdadamemd 提供,位于 Wikimedia Commons 上。