改进的暗黑模式默认样式,使用 color-scheme CSS 属性和相应的 meta 标签

color-scheme CSS 属性和相应的 meta 标签允许开发者选择将其页面加入用户代理样式表的主题特定默认样式。

背景

prefers-color-scheme 用户偏好媒体功能

prefers-color-scheme 用户偏好媒体功能使开发者能够完全控制其页面的外观。如果您对此不熟悉,请阅读我的文章 prefers-color-scheme:你好,黑暗,我的老朋友,我在其中记录了我所知道的关于创建出色暗黑模式体验的一切。

文章中仅简要提及的一个难题是 color-scheme CSS 属性和同名的相应 meta 标签。它们都通过允许您选择将其页面加入用户代理样式表的主题特定默认样式(例如,表单控件、滚动条以及 CSS 系统颜色),从而使您作为开发者的生活更轻松。同时,此功能可防止浏览器自行应用任何转换。

浏览器支持

prefers-color-scheme

浏览器支持

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 67.
  • Safari: 12.1.

来源

color-scheme

浏览器支持

  • Chrome: 81.
  • Edge: 81.
  • Firefox: 96.
  • Safari: 13.

来源

用户代理样式表

在继续之前,请允许我简要描述一下什么是用户代理样式表。大多数时候,您可以将用户代理 (UA) 一词视为表示浏览器的一种花哨方式。UA 样式表决定了页面的默认外观。顾名思义,UA 样式表是取决于相关 UA 的东西。您可以查看 Chrome(和 Chromium)的 UA 样式表,并将其与 FirefoxSafari(和 WebKit)的 UA 样式表进行比较。通常,UA 样式表在大多数方面都达成一致。例如,它们都将链接设置为蓝色,将普通文本设置为黑色,并将背景颜色设置为白色,但也存在重要的(有时是令人讨厌的)差异,例如,它们如何设置表单控件的样式。

仔细查看 WebKit 的 UA 样式表,以及它在暗黑模式方面的作用。(在样式表中全文搜索“dark”。)样式表提供的默认设置会根据暗黑模式是开启还是关闭而更改。为了说明这一点,以下是使用 :matches 伪类和 WebKit 内部变量(如 -apple-system-control-background)以及 WebKit 内部预处理器指令 #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 */
}

您会注意到上面 colorbackground-color 属性的一些非标准值。text-apple-system-control-background 都不是有效的 CSS 颜色。它们是 WebKit 内部语义颜色。

事实证明,CSS 已标准化语义系统颜色。它们在 CSS Color Module Level 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 Color Adjustment Module Level 1 规范引入了一种模型,并通过用户代理对自动颜色调整进行控制,目的是处理用户偏好,例如暗黑模式、对比度调整或特定的所需配色方案。

其中定义的 color-scheme 属性允许元素指示它可以舒适地呈现哪些配色方案。这些值与用户的偏好进行协商,从而产生一个选定的配色方案,该方案会影响用户界面 (UI) 事物,例如表单控件和滚动条的默认颜色,以及 CSS 系统颜色的使用值。目前支持以下值

  • normal 表示该元素完全不知道配色方案,因此应以浏览器的默认配色方案呈现该元素。

  • [ light | dark ]+ 表示该元素知道并可以处理列出的配色方案,并表达它们之间的有序偏好。

在此列表中,light 表示浅色配色方案,具有浅色背景颜色和深色前景颜色,而 dark 表示相反的情况,具有深色背景颜色和浅色前景颜色。

对于所有元素,使用配色方案进行渲染应使元素所有浏览器提供的 UI 中使用的颜色与配色方案的意图相匹配。示例包括滚动条、拼写检查下划线、表单控件等。

:root 元素上,使用配色方案渲染还必须影响画布的表面颜色(即,全局背景颜色)、color 属性的初始值以及系统颜色的使用值,并且还应影响视口的滚动条。

/*
  The page supports both dark and light color schemes,
  and the page author prefers dark.
*/
:root {
  color-scheme: dark light;
}

color-scheme meta 标签

遵循 color-scheme CSS 属性需要首先下载 CSS(如果通过 <link rel="stylesheet"> 引用),然后进行解析。为了帮助用户代理立即使用所需的配色方案呈现页面背景,也可以在 <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-schemeprefers-color-scheme

由于 meta 标签和 CSS 属性(如果应用于 :root 元素)最终都会产生相同的行为,因此我始终建议通过 meta 标签指定配色方案,以便浏览器可以更快地适应首选方案。

虽然对于绝对基线页面,不需要额外的 CSS 规则,但在一般情况下,您应始终将 color-schemeprefers-color-scheme 结合使用。例如,WebKit 和 Chrome 用于经典链接蓝色 rgb(0,0,238) 的专有 WebKit CSS 颜色 -webkit-link 在黑色背景上的对比度不足,仅为 2.23:1,并且 未通过 WCAG AA 以及 WCAG AAA 要求

我已经为 ChromeWebKitFirefox 以及 HTML 标准中的 meta 问题 提交了错误报告,以解决此问题。

prefers-color-scheme 的相互作用

color-scheme CSS 属性和相应的 meta 标签与 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

A page in light mode.
浅色模式: 由开发者和用户代理指定的样式。根据用户代理样式表,文本为黑色,背景为白色。<fieldset> 元素的 background-color 根据内联开发者样式表为 gainsboro
A page in dark mode.
暗黑模式: 由开发者和用户代理指定的样式。根据用户代理样式表,文本为白色,背景为黑色。<fieldset> 元素的 background-color 根据内联开发者样式表为 darkslategray

<button> 元素的外观由用户代理样式表控制。其 color 设置为 ButtonText 系统颜色,其 background-color 和四个 border-color 设置为系统颜色 ButtonFace

A light mode page that uses the ButtonFace property.
浅色模式: background-color 和各种 border-color 设置为 ButtonFace 系统颜色。

现在请注意 <button> 元素的 border-color 如何变化。border-top-colorborder-bottom-color计算值从 rgba(0, 0, 0, 0.847)(黑色)切换到 rgba(255, 255, 255, 0.847)(白色),因为用户代理会根据配色方案动态更新 ButtonFace。这同样适用于设置为相应系统颜色 ButtonText<button> 元素的 color

Showing that the computed color values match ButtonFace.
浅色模式: 用户代理样式表中都设置为 ButtonFaceborder-top-colorborder-bottom-color 的计算值现在为 rgba(0, 0, 0, 0.847)
Showing that the computed color values still match ButtonFace while in dark mode.
暗黑模式: 用户代理样式表中都设置为 ButtonFaceborder-top-colorborder-bottom-color 的计算值现在为 rgba(255, 255, 255, 0.847)

演示

您可以在 Glitch 上的演示中查看应用于大量 HTML 元素的 color-scheme 的效果。该演示故意显示了上述警告中提到的链接颜色的 WCAG AA 和 WCAG AAA 违规

The demo while in light mode.
切换到 color-scheme: light演示
The demo while in dark mode.
切换到 color-scheme: dark演示。请注意链接颜色的 WCAG AA 和 WCAG AAA 违规

致谢

color-scheme CSS 属性和相应的 meta 标签由 Rune Lillesveen 实现。Rune 也是 CSS Color Adjustment Module Level 1 规范的共同编辑。题图由 Philippe LeoneUnsplash 上提供。