借助 color-scheme
CSS 属性和相应的元标记,开发者可以为自己的网页选择采用用户代理样式表针对具体主题的默认值。
背景
prefers-color-scheme
用户偏好设置媒体功能
借助 prefers-color-scheme
用户偏好设置媒体功能,开发者能够完全控制其页面的外观。如果您不熟悉,请阅读我的文章“prefers-color-scheme
:嗨,我的老朋友,深色模式!”,其中记录了我所知道的关于打造令人惊叹的深色模式体验的所有信息。
我们在本文中简要提及了其中一部分内容,即 color-scheme
CSS 属性和对应的同名元标记。它们都允许您为页面选择启用用户代理样式表针对具体主题的默认值(例如表单控件、滚动条以及 CSS 系统颜色),从而简化开发者的工作。同时,此功能可防止浏览器自行应用任何转换。
浏览器支持
prefers-color-scheme
color-scheme
用户代理样式表
在继续之前,我先简要描述一下什么是用户代理样式表。大多数情况下,您可以将“用户代理”(UA) 一词视为“浏览器”的花样表达。UA 样式表决定了页面的默认外观和风格。顾名思义,UA 样式表依赖于相关 UA。您可以查看 Chrome(和 Chromium)的 UA 样式表,并将其与 Firefox 或 Safari(以及 WebKit)的 UA 样式表进行比较。通常情况下,UA 样式表在大多数方面达成一致。例如,它们将链接设为蓝色、常规文本为黑色、背景颜色为白色,但两者之间也存在一些重要(有时非常烦人)的差异,例如,它们在表单控件的样式方面有何不同。
请仔细查看 WebKit 的 UA 样式表及其在深色模式下执行的操作。(在样式表中搜索“dark”进行全文搜索。)
样式表提供的默认值会根据深色模式处于开启还是关闭状态而变化。为了说明这一点,下面是一个使用 :matches
伪类和 WebKit 内部变量(如 -apple-system-control-background
)以及 WebKit-internal 预处理器指令 #if defined
的此类 CSS 规则:
input,
input:matches([type="password"], [type="search"]) {
-webkit-appearance: textfield;
#if defined(HAVE_OS_DARK_MODE_SUPPORT) &&
HAVE_OS_DARK_MODE_SUPPORT
color: text;
background-color: -apple-system-control-background;
#else
background-color: white;
#endif
/* snip */
}
您会注意到上面的 color
和 background-color
属性有一些非标准值。text
和 -apple-system-control-background
都不是有效的 CSS 颜色。它们是 WebKit 内部的语义颜色。
事实证明,CSS 具有标准化的语义系统颜色。这些颜色在 CSS 颜色模块级别 4 中指定。例如,Canvas
(不要与 <canvas>
标记混淆)表示应用内容或文档的背景,而 CanvasText
表示应用内容或文档中的文本。这两者需要搭配使用,不能单独使用。
UA 样式表可以使用自己的专有颜色或标准化语义系统颜色来确定 HTML 元素在默认情况下应如何呈现。如果操作系统设置为深色模式或使用深色主题,系统会有条件地将 CanvasText
(或 text
)设置为白色,并将 Canvas
(或 -apple-system-control-background
)设置为黑色。然后,UA 样式表仅分配以下 CSS 一次,涵盖浅色模式和深色模式。
/**
Not actual UA stylesheet code.
For illustrative purposes only.
*/
body {
color: CanvasText;
background-color: Canvas
}
color-scheme
CSS 属性
CSS 颜色调整模块级别 1 规范引入了一个模型,可控制用户代理进行的自动颜色调整,其目的是处理用户偏好设置(例如深色模式、对比度调整或所需的特定配色方案)。
其中定义的 color-scheme
属性允许元素指明适合呈现的配色方案。这些值根据用户的偏好进行协商,从而选定会影响界面 (UI) 的内容,例如表单控件和滚动条的默认颜色以及 CSS 系统颜色所使用的值。目前支持以下值:
normal
表示元素完全不知道配色方案,因此应按照浏览器的默认配色方案渲染此元素。[ light | dark ]+
表示此元素了解并可以处理列出的配色方案,并表示这些配色方案之间的有序偏好设置。
在此列表中,light
表示浅色方案,背景色为浅色,前景色为深色,而 dark
表示相反,使用深色背景色和浅色前景色。
对于所有元素,使用配色方案呈现时,浏览器为相应元素提供的所有界面中使用的颜色都应与配色方案的意图一致。示例包括滚动条、拼写检查下划线、表单控件等。
在 :root
元素上,使用配色方案进行渲染还必须影响画布的 Surface 颜色(即全局背景颜色)、color
属性的初始值和使用的系统颜色值,并且还应影响视口的滚动条。
/*
The page supports both dark and light color schemes,
and the page author prefers dark.
*/
:root {
color-scheme: dark light;
}
color-scheme
元标记
遵循 color-scheme
CSS 属性需要首先下载 CSS(如果通过 <link rel="stylesheet">
引用 CSS)并对其进行解析。为了帮助用户代理立即使用所需的配色方案呈现网页背景,还可以在 <meta name="color-scheme">
元素中提供 color-scheme
值。
<!--
The page supports both dark and light color schemes,
and the page author prefers dark.
-->
<meta name="color-scheme" content="dark light">
合并 color-scheme
和 prefers-color-scheme
由于元标记和 CSS 属性(如果应用于 :root
元素)最终会导致相同的行为,因此我始终建议通过元标记指定配色方案,以便浏览器更快地采用首选方案。
虽然对于绝对基准网页,不需要额外的 CSS 规则,但一般情况下,您应始终将 color-scheme
与 prefers-color-scheme
结合使用。例如,WebKit 和 Chrome 为经典链接蓝色 rgb(0,0,238)
使用的专有 WebKit CSS 颜色 -webkit-link
在黑色背景上的对比度不足 2.23:1,并且不符合 WCAG AA 和 WCAG AAA 要求。
我已为 Chrome、WebKit 和 Firefox 报告了一个 bug,还开启了 HTML 标准中的一个元问题来修复此问题。
与prefers-color-scheme
互动
color-scheme
CSS 属性以及相应元标记与 prefers-color-scheme
用户偏好设置媒体功能的相互作用一开始可能会让人感到困惑。事实上,它们配合得很出色。
最重要的一点是,color-scheme
专门决定默认外观,而 prefers-color-scheme
则决定样式化外观。为清楚起见,我们以下面的页面为例进行说明:
<head>
<meta name="color-scheme" content="dark light">
<style>
fieldset {
background-color: gainsboro;
}
@media (prefers-color-scheme: dark) {
fieldset {
background-color: darkslategray;
}
}
</style>
</head>
<body>
<p>
Lorem ipsum dolor sit amet, legere ancillae ne vis.
</p>
<form>
<fieldset>
<legend>Lorem ipsum</legend>
<button type="button">Lorem ipsum</button>
</fieldset>
</form>
</body>
一般情况下,网页上的内嵌 CSS 代码会将 <fieldset>
元素的 background-color
设置为 gainsboro
;如果用户更喜欢根据 prefers-color-scheme
用户偏好设置媒体功能采用 dark
配色方案,则设置为 darkslategray
。
通过 <meta name="color-scheme" content="dark light">
元素,网页会告知浏览器它支持深色主题和浅色主题,并优先使用深色主题。
根据用户代理样式表,整个页面会以深色模式呈现,反之亦然,具体取决于操作系统是设置为深色模式还是浅色模式。更改段落文本或页面的背景颜色时,不涉及开发者提供的其他 CSS。
请注意,按照开发者提供的内嵌样式表中的规则,<fieldset>
元素的 background-color
会因是否启用了深色模式而发生变化。为 gainsboro
或 darkslategray
。
![处于浅色模式的网页。](https://web.developers.google.cn/static/articles/color-scheme/image/a-page-light-mode-20033c5b52e57.png?authuser=5&hl=hr)
<fieldset>
元素的 background-color
为 gainsboro
。
![深色模式的页面。](https://web.developers.google.cn/static/articles/color-scheme/image/a-page-dark-mode-db72ce14278ec.png?authuser=5&hl=hr)
<fieldset>
元素的 background-color
为 darkslategray
。
<button>
元素的外观由用户代理样式表控制。其 color
设置为 ButtonText
系统颜色,其 background-color
和四个 border-color
设置为系统颜色 ButtonFace
。
![使用 ButtonFace 属性的浅色模式页面。](https://web.developers.google.cn/static/articles/color-scheme/image/a-light-mode-page-uses-2d1dbd77e94d4.png?authuser=5&hl=hr)
background-color
和各种 border-color
均设置为 ButtonFace 系统颜色。
现在,请注意 <button>
元素的 border-color
是如何变化的。border-top-color
和 border-bottom-color
的 computed 值从 rgba(0, 0, 0, 0.847)
(黑色)切换为 rgba(255, 255, 255, 0.847)
(白色),因为用户代理根据配色方案动态更新 ButtonFace
。这同样适用于设置为相应系统颜色 ButtonText
的 <button>
元素的 color
。
![显示计算出的颜色值与 ButtonFace 匹配。](https://web.developers.google.cn/static/articles/color-scheme/image/showing-the-computed-col-b5a5bb27a14d7.png?authuser=5&hl=hr)
ButtonFace
的 border-top-color
和 border-bottom-color
的计算值现在为 rgba(0, 0, 0, 0.847)
。
![显示在深色模式下,计算的颜色值仍与 ButtonFace 匹配。](https://web.developers.google.cn/static/articles/color-scheme/image/showing-the-computed-col-fbfce1c6513a9.png?authuser=5&hl=hr)
ButtonFace
的 border-top-color
和 border-bottom-color
的计算值现在为 rgba(255, 255, 255, 0.847)
。
演示
您可以在 Glitch 上的演示中查看 color-scheme
应用于大量 HTML 元素的效果。该演示故意显示了 WCAG AA 和 WCAG AAA 违规行为,并使用了上述警告中提及的链接颜色。
![浅色模式下的演示](https://web.developers.google.cn/static/articles/color-scheme/image/the-demo-while-light-mod-8d16b35fd6de9.png?authuser=5&hl=hr)
color-scheme: light
。
![深色模式下的演示。](https://web.developers.google.cn/static/articles/color-scheme/image/the-demo-while-dark-mode-9f130b7310353.png?authuser=5&hl=hr)
color-scheme: dark
的演示。
请注意链接颜色的 WCAG AA 和 WCAG AAA
违规行为
。
致谢
color-scheme
CSS 属性和相应的元标记由 Rune Lillesveen 实现。Rune 还是 CSS 颜色调整模块级别 1 规范的共同编辑者。主打图片,由 Philippe Leone 提供,由 Unspin 提供。