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

借助一组客户端提示标头,网站可以在请求时选择性地获取用户的媒体偏好设置,从而使服务器能够出于性能考虑而内嵌正确的 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 响应标头,服务器可以使用该标头来宣传其使用请求标头进行主动内容协商(俗称“客户端提示”)。用户偏好媒体功能客户端提示标头提案定义了一组旨在传达用户偏好媒体功能的客户端提示。这些客户端提示以其报告的相应用户偏好媒体功能命名。 例如,当前首选的配色方案(如 prefers-color-scheme 中所示)通过名为 Sec-CH-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) {}

客户端提示的完整列表

客户端提示列表是根据媒体查询级别 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 的演示

您可以尝试演示,并注意内嵌 CSS 如何根据用户的首选配色方案而变化。您可以在 GitHub 上找到源代码

Sec-CH-Prefers-Color-Scheme: dark

Sec-CH-Prefers-Color-Scheme: light

Sec-CH-Prefers-Reduced-Motion 的演示

试用演示,并注意内嵌 CSS 如何根据用户的运动偏好设置而变化。您可以在 GitHub 上找到源代码

运作方式

  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 提供的宝贵反馈和建议。 维基共享资源Tdadamemd 创作的主打图片。