用户偏好设置媒体功能客户端提示标头

通过一组客户端提示标头,网站可以选择在请求时获取用户的媒体偏好设置,以便服务器出于性能方面的考虑内嵌正确的 CSS。

CSS 媒体查询,尤其是 prefers-color-schemeprefers-reduced-motion用户偏好媒体功能,可能会对网页需要传送的 CSS 量以及用户在网页加载时获得的体验产生重大影响

重点介绍 prefers-color-scheme,但强调该推理也适用于其他用户偏好设置媒体功能。最佳实践是,不要在关键渲染路径中加载特定不匹配配色方案的 CSS,而是在初始阶段仅加载当前相关的 CSS。一种方法是通过 <link media> 执行此操作。

不过,如果Google 搜索等高流量网站希望遵循用户偏好媒体功能(例如 prefers-color-scheme)并出于性能原因内嵌 CSS,则最好在请求时了解首选配色方案(或其他用户偏好媒体功能),以便初始 HTML 载荷中已内嵌正确的 CSS。

此外,对于 prefers-color-scheme,网站会尽量避免闪烁不准确的配色主题

Sec-CH-Prefers-Color-SchemeSec-CH-Prefers-Reduced-Motion 客户端提示标头是旨在解决此问题的一系列用户偏好设置媒体功能客户端提示标头中的第一个。

客户端提示背景知识

HTTP 客户端提示定义了一个 Accept-CH 响应标头,服务器可以使用该响应标头通告其使用请求标头进行主动内容协商(俗称为客户端提示)。用户偏好媒体功能客户端提示标头提案定义了一组旨在传达用户偏好媒体功能的客户端提示。这些客户端提示的命名方式与其报告的对应用户偏好媒体功能相同。例如,系统会通过恰当命名的 Sec-CH-Prefers-Color-Scheme 客户端提示报告当前根据 prefers-color-scheme 的首选配色方案。

关键客户端提示背景信息

用户偏好设置媒体功能客户端提示标头中建议的客户端提示一般可用作关键客户端提示。关键客户端提示是指会对生成的资源产生实质性更改的客户端提示。在每次网页加载(包括初始网页加载)时,都应一致提取此类资源,以避免用户看到突兀的切换。

客户端提示语法

用户偏好媒体功能由名称(例如 prefers-reduced-motion)和允许的值(例如 no-preferencereduce)组成。每个客户端提示标头字段都表示为包含一个值为字符串HTTP 的结构化标头对象。例如,如需表明用户更喜欢深色主题并减少动态,客户端提示应如以下示例所示。

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) {}

客户端提示的完整列表

客户端提示列表以 Media Queries Level 5 中的用户偏好媒体功能为蓝本。

客户端提示 允许的值 对应的用户偏好设置媒体功能
Sec-CH-Prefers-Reduced-Motion no-preferencereduce prefers-reduced-motion
Sec-CH-Prefers-Reduced-Transparency no-preferencereduce prefers-reduced-transparency
Sec-CH-Prefers-Contrast no-preferencelessmorecustom prefers-contrast
Sec-CH-Forced-Colors activenone forced-colors
Sec-CH-Prefers-Color-Scheme lightdark prefers-color-scheme
Sec-CH-Prefers-Reduced-Data no-preferencereduce prefers-reduced-data

浏览器支持

Chromium 93 支持 Sec-CH-Prefers-Color-Scheme 客户端提示标头。 Chromium 108 支持 Sec-CH-Prefers-Reduced-Motion 客户端提示标头。其他供应商(即 WebKitMozilla)的反馈仍待处理。

Sec-CH-Prefers-Color-Scheme 演示

在 Chromium 93 中试用演示版,并注意内嵌 CSS 如何根据用户的首选配色方案而变化。

Sec-CH-Prefers-Color-Scheme:深色

Sec-CH-Prefers-Color-Scheme: light

Sec-CH-Prefers-Reduced-Motion 演示

在 Chromium 108 中试用演示版,并注意内嵌 CSS 如何根据用户的动作偏好设置而变化。

工作原理

  1. 客户端向服务器发出初始请求。 bash GET / HTTP/2 Host: example.com
  2. 服务器会做出响应,并通过 Accept-CH 告知客户端它接受 Sec-CH-Prefers-Color-SchemeSec-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
  3. 然后,客户端会重试请求,通过 Sec-CH-Prefers-Color-Scheme 告知服务器其用户偏好使用深色主题的内容。bash GET / HTTP/2 Host: example.com Sec-CH-Prefers-Color-Scheme: "dark"
  4. 然后,服务器可以根据客户端的偏好设置量身定制响应,例如,将负责深色主题的 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 客户端提示的安全注意事项和客户端提示可靠性的安全注意事项同样适用于此提案。

参考

致谢

非常感谢 Yoav Weiss 提供宝贵的反馈和建议。主打图片来自 Wikimedia CommonsTdadamemd