Preferreds-color-scheme:你好,黑暗,我的老朋友

过度宣传或必要?详细了解深色模式以及如何支持深色模式,从而让用户受益!

简介

系统会优先采用深色模式,然后再采用深色模式

<ph type="x-smartling-placeholder">
</ph> 绿幕计算机显示器
绿幕(来源

深色模式已经实现了一个圆环。 在个人计算发展初期,深色模式并不是选择, 但事实上 通过发射电子束工作的单色 CRT 计算机显示器 在荧光屏上,早期 CRT 中使用的荧光为绿色。 由于文本以绿色显示,屏幕其余部分为黑色,因此这些模型通常被称为 绿幕

<ph type="x-smartling-placeholder">
</ph> 深白文字处理
深白色(来源

随后引入的 Color CRT 可显示多种颜色 通过使用红色、绿色和蓝色荧光体的能量 他们通过同时激活全部三种荧光体生成白色。 随着更加复杂的所见即所得方法的问世 桌面发布、 让虚拟文档看起来像一张纸质纸张的想法越来越受欢迎。

<ph type="x-smartling-placeholder">
</ph> 万维网浏览器中的暗白网页
万维网浏览器(来源

就从这里开始采用深色配白色作为设计趋势, 这一趋势也随之延续到了 早期基于文档的网络。 第一款浏览器 WorldWideWeb (请注意, CSS 甚至还没有发明), 显示的网页。 有趣的事实:第二个浏览器 Line Mode Browser(基于终端的浏览器) 深色配绿色。 如今,网页和 Web 应用通常采用深色文本设计 以浅色背景为基础,假设基准假设也已硬编码到用户代理样式表中,包括 Chrome 的

<ph type="x-smartling-placeholder">
</ph> 躺在床上的智能手机
在床上使用的智能手机(来源:Unsplash)

CRT 的时代已然结束。 内容消费和创作已转向移动设备 (采用背光 LCD) 或节能 AMOLED 屏幕。 体积更小、便于携带的计算机、平板电脑和智能手机带来了新的使用模式。 完成休闲任务,例如浏览网页、编码娱乐游戏和玩游戏 常常在下班后在昏暗的环境中发生。 人们甚至在晚上喜欢在自己的床上使用设备。 如今,越来越多的人在黑暗中 追溯光明变暗理念的理念越流行。

为何使用深色模式

出于美观原因使用深色模式

当有人询问时 用户喜欢或想要使用深色模式的原因 最热门的回答是“看上去更省力” 以及“它优雅而美丽”。 在他们的 深色模式开发者文档 明确写道:“选择是启用浅色还是深色外观” 对大多数用户而言都是美观的设计,可能与环境光照条件无关。”

。 <ph type="x-smartling-placeholder">
</ph> Mac OS 7 中的 CloseView
系统 7 CloseView(来源

将深色模式用作无障碍工具

还有一些人确实需要深色模式,并将它用作其他无障碍工具, 例如,视力不佳的用户 我能找到最早的这类无障碍工具是 系统 7CloseView 功能,其中包含一个用于 白底黑字黑底白字。 虽然系统 7 支持颜色,但默认界面仍然是黑白的。

引入颜色后,这些基于反转的实现展示了它们的弱点。 Szpiro 等人对 低视力用户如何使用计算设备 表明所有受访用户都不喜欢倒置的图片, 但在深色背景上更喜欢浅色文本。 Apple 通过一项称为 Smart Invert, 这会反转显示屏的颜色,但图片、媒体和 以及一些采用深色样式的应用。

一种特殊形式的低视力是计算机视觉综合征,也称为数字眼疲劳, 已定义 “与计算机使用相关的眼睛和视觉问题” 和其他电子显示屏(例如 “智能手机和电子阅读设备”)。提议 青少年使用电子设备,尤其是在晚上 会导致睡眠时间较短的风险增加, 睡眠开始延迟更长以及睡眠不足。 此外,人们普遍认为蓝光暴露 已报告 能够参与 昼夜节律 和睡眠周期之间的变化, 和不规律的光线环境都可能会导致睡眠不足 可能会影响情绪和任务的表现 Roenfield 的研究。 为了减少这些负面影响,可以通过调整显示屏的色温来减少蓝光 例如通过 iOS 的夜间模式或 Android 的 护眼模式可以派上用场 以及通过深色主题或深色模式避免笼统的亮光或不规律的光线

AMOLED 屏幕采用深色模式省电

最后,众所周知,深色模式可以节省 AMOLED 屏幕。 侧重于热门 Google 应用的 Android 案例研究 如 YouTube 已经显示,最多可节省 60% 的电量。 下面的视频详细介绍了这些案例研究以及每个应用的省电功能。

在操作系统中启用深色模式

现在,我了解了为何深色模式对许多用户如此重要的原因, 我们来看一下如何提供支持

<ph type="x-smartling-placeholder">
</ph> Android Q 深色模式设置
Android Q 深色主题设置

支持深色模式或深色主题的操作系统 通常可以在设置中的某个位置选择启用该功能。 在 macOS X 上,此选项位于系统偏好设置的 General 部分,且名为 Appearance屏幕截图), 在 Windows 10 设备上,该图标位于颜色部分,并且名为选择您的颜色屏幕截图)。 对于 Android Q,您可以在显示下以深色主题切换开关的形式找到它(屏幕截图)。 在 iOS 13 上,您可以在显示和亮度 部分(屏幕截图)。

prefers-color-scheme 媒体查询

在开始之前,我们要介绍最后一点理论。 媒体查询 允许作者测试和查询用户代理或显示设备的值或功能; 与正在渲染的文档无关。 在 CSS @media 规则中使用它们有条件地将样式应用于文档, 以及其他各种上下文和语言,例如 HTML 和 JavaScript。 媒体查询 5 级 引入了所谓的用户偏好媒体功能,即 使网站检测用户首选的内容显示方式的方法。

prefers-color-scheme 媒体功能来检测 如果用户请求网页使用浅色或深色主题,就会触发展示。 它使用以下值:

  • light: 表示用户已通知系统他们偏好使用浅色主题的网页 (深色文字配浅色背景)。
  • dark: 表示用户已通知系统他们偏好使用深色主题的页面 (浅色文字配深色背景)。

支持深色模式

了解浏览器是否支持深色模式

由于深色模式是通过媒体查询报告的,因此您可以轻松检查 支持深色模式,方法是检查媒体查询 prefers-color-scheme 是否完全匹配。 请注意,我不添加任何值,但仅用于检查媒体查询是否单独匹配。

if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') {
  console.log('🎉 Dark mode is supported');
}

在撰写本文时,桌面设备和移动设备均支持 prefers-color-scheme(如果可用) Chrome 和 Edge(从版本 76 开始)、Firefox(从版本 67 开始) 和 Safari(macOS 上的版本 12.1 及更高版本)和 Safari(iOS 上的版本 13)。 对于所有其他浏览器,您可以参阅我可以使用支持表格

在请求时了解用户的偏好设置

Sec-CH-Prefers-Color-Scheme 客户端提示标头 允许网站在请求时获取用户的配色方案偏好设置, 允许服务器内嵌正确的 CSS,从而避免闪烁不正确的色彩主题。

深色模式实际应用

最后,我们来看一下支持深色模式的实际情形。 就像 Highlander 的作品一样, 深色模式只能有一种:深色或浅色,但不可同时使用两者! 为什么我要提及这一点?因为这应该会对加载策略产生影响。 请勿强制用户在关键呈现路径中下载 CSS 针对他们目前未使用的模式发出了通知。 为了优化加载速度,我为示例应用拆分了 CSS 展示了以下实际应用建议 分为三个部分,以推迟非关键 CSS

  • style.css,其中包含网站普遍使用的通用规则。
  • dark.css,仅包含深色模式所需的规则。
  • light.css,仅包含轻量模式所需的规则。

正在加载策略

后两个应用(light.cssdark.css) 使用 <link media> 查询有条件地加载。 最初, 并非所有浏览器都支持 prefers-color-scheme (可使用上述模式检测到), 我可以通过加载默认的light.css文件来动态处理 通过在小型内嵌脚本中有条件地插入 <link rel="stylesheet"> 元素 (浅色是任意选择,我也可以将深色设置为默认的后备体验)。 为避免闪烁无样式的内容, 我会一直隐藏网页内容,直到 light.css 加载完毕。

<script>
  // If `prefers-color-scheme` is not supported, fall back to light mode.
  // In this case, light.css will be downloaded with `highest` priority.
  if (window.matchMedia('(prefers-color-scheme: dark)').media === 'not all') {
    document.documentElement.style.display = 'none';
    document.head.insertAdjacentHTML(
      'beforeend',
      '<link rel="stylesheet" href="/light.css" onload="document.documentElement.style.display = \'\'">',
    );
  }
</script>
<!--
  Conditionally either load the light or the dark stylesheet. The matching file
  will be downloaded with `highest`, the non-matching file with `lowest`
  priority. If the browser doesn't support `prefers-color-scheme`, the media
  query is unknown and the files are downloaded with `lowest` priority (but
  above I already force `highest` priority for my default light experience).
-->
<link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)" />
<link
  rel="stylesheet"
  href="/light.css"
  media="(prefers-color-scheme: light)"
/>
<!-- The main stylesheet -->
<link rel="stylesheet" href="/style.css" />

样式表架构

我充分利用了 CSS 变量, 这样就可以使通用 style.css 成为通用的 所有浅色或深色模式自定义设置都发生在另外两个文件 dark.csslight.css 中。 您可以在下面看到实际样式的摘录,但这应该足以传达总体思路。 我声明了两个变量:-⁠-⁠color-⁠-⁠background-color 它们实质上是创建 dark-on-lightlight-on-dark 基准主题。

/* light.css: 👉 dark-on-light */
:root {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
}
/* dark.css: 👉 light-on-dark */
:root {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
}

然后,在 style.css 中,我在 body { … } 规则中使用这些变量。 与 :root CSS 伪类 - 选择器,在 HTML 中表示 <html> 元素 它与选择器 html 完全相同,只不过它的特异性是 它们会向下级联,以便我声明全局 CSS 变量。

/* style.css */
:root {
  color-scheme: light dark;
}

body {
  color: var(--color);
  background-color: var(--background-color);
}

在上面的代码示例中,您可能已经注意到 color-scheme 替换为以空格分隔的值 light dark

此属性告知浏览器我的应用支持哪些颜色主题 并允许它激活用户代理样式表的特殊变体, 例如,可以让浏览器显示表单字段 深色背景和浅色文字,调整滚动条 或启用主题感知突出显示颜色。 color-scheme 的确切详情参见 CSS 颜色调整模块级别 1

其他所有操作都只需定义 CSS 变量 提供重要数据 使用深色模式时,从语义层面整理样式会很有帮助。 例如,考虑调用变量,而不是 -⁠-⁠highlight-yellow -⁠-⁠accent-color,显示为“黄色”在深色模式下可能未呈现黄色,反之亦然。 以下是我在示例中使用的一些其他变量的示例。

/* dark.css */
:root {
  --color: rgb(250, 250, 250);
  --background-color: rgb(5, 5, 5);
  --link-color: rgb(0, 188, 212);
  --main-headline-color: rgb(233, 30, 99);
  --accent-background-color: rgb(0, 188, 212);
  --accent-color: rgb(5, 5, 5);
}
/* light.css */
:root {
  --color: rgb(5, 5, 5);
  --background-color: rgb(250, 250, 250);
  --link-color: rgb(0, 0, 238);
  --main-headline-color: rgb(0, 0, 192);
  --accent-background-color: rgb(0, 0, 238);
  --accent-color: rgb(250, 250, 250);
}

完整示例

在以下 Glitch 嵌入中, 您可以看到将上述概念付诸实践的完整示例。 尝试在特定操作系统的设置中开启/关闭深色模式 看看网页会如何反应

加载影响

使用以下示例时,您可以 为何通过媒体查询加载 dark.csslight.css。 尝试切换深色模式并重新加载页面: 系统仍会加载当前不匹配的特定样式表,但优先级最低, 确保它们永远不会与网站目前所需的资源竞争。

。 <ph type="x-smartling-placeholder">
</ph> 网络加载示意图,显示在浅色模式下,深色模式 CSS 如何以最低优先级加载
在浅色模式下的网站会加载优先级最低的深色模式 CSS。
。 <ph type="x-smartling-placeholder">
</ph> 网络加载示意图,展示了在深色模式下,系统如何以最低优先级加载浅色模式 CSS
深色模式下的网站会加载优先级最低的浅色模式 CSS。
。 <ph type="x-smartling-placeholder">
</ph> 网络加载示意图,显示在默认浅色模式下,深色模式 CSS 如何以最低优先级加载
在不支持 prefers-color-scheme 的浏览器上,网站采用默认浅色模式时,会加载优先级最低的深色模式 CSS。

对深色模式变化做出响应

与任何其他媒体查询更改一样,您可以通过 JavaScript 订阅深色模式更改。 例如,您可以使用此参数动态更改 网站图标 或更改网页的 <meta name="theme-color"> 决定 Chrome 中网址栏的颜色。 上面的完整示例展示了这一操作的实际应用: 要查看主题颜色和网站图标的变化,请打开 在单独的标签页中进行演示

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeMediaQuery.addEventListener('change', (e) => {
  const darkModeOn = e.matches;
  console.log(`Dark mode is ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
});

从 Chromium 93 和 Safari 15 开始,您可以根据 媒体查询(使用 meta 主题颜色元素的 media 属性)。通过 系统会选择第一个与它匹配的项例如,您可以为 另一个用于深色模式在撰写本文时,您不能 请在清单中定义这些内容请参阅 w3c/manifest#975 GitHub 问题

<meta
  name="theme-color"
  media="(prefers-color-scheme: light)"
  content="white"
/>
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black" />

调试和测试深色模式

在开发者工具中模拟 prefers-color-scheme

整个操作系统的配色方案切换起来可能会很烦人, 因此,Chrome 开发者工具现在允许您模拟用户的首选配色方案 而只会影响当前显示的标签页 打开命令菜单,开始输入 Rendering,运行 Show Rendering 命令,然后更改 Emulate CSS media feature preferences-color-scheme 选项。

“Emulate CSS media feature preferences-color-scheme”的屏幕截图选项(位于 Chrome 开发者工具的“渲染”标签页中)

使用 Puppeteer 截取 prefers-color-scheme 屏幕截图

Puppeteer 是一个 Node.js 库 ,该 API 提供了一个高级 API,可通过该 API 通过 DevTools 协议。 对于dark-mode-screenshot,我们提供: 一个 Puppeteer 脚本,让您可以在深色模式和浅色模式下创建网页的屏幕截图。 您可以一次性运行此脚本,也可以将其作为 持续集成 (CI) 测试套件。

npx dark-mode-screenshot --url https://googlechromelabs.github.io/dark-mode-toggle/demo/ --output screenshot --fullPage --pause 750

有关深色模式的最佳实践

避免使用纯白色

你可能已经注意到一个小细节:我没有使用纯白色。 而是要避免在周围的深色内容中出现发光和出血的情况, 我选择稍深的白色。使用 rgb(250, 250, 250) 之类的代码就可以了。

对摄影图片重新着色和调暗

如果比较下面的两个屏幕截图,您会注意到,不仅核心主题发生了变化 从 dark-on-light 更改为 light-on-dark,但主打图片看起来也略有不同。 我的用户调查 表明,大部分受访用户 启用深色模式时,建议选择颜色稍稍不太鲜艳的图片。 我称之为“重新着色”。

<ph type="x-smartling-placeholder">
</ph> 在深色模式下,主打图片会略微变暗。 <ph type="x-smartling-placeholder">
</ph> 在深色模式下,主打图片会略微变暗。
<ph type="x-smartling-placeholder">
</ph> 浅色模式下的常规主打图片。
浅色模式下的常规主打图片。

通过对图片应用 CSS 过滤器可以实现重新着色。 我使用的 CSS 选择器可以匹配网址中没有 .svg 的所有图片, 我的想法是,对矢量图形(图标)采用不同的重新着色处理 ,下一段落将详细介绍这方面的内容。 请注意,我再次使用 CSS 变量后, 以便稍后灵活更改过滤器

由于只有在深色模式下才需要重新着色,即当 dark.css 处于启用状态时, “light.css”中没有对应的规则。

/* dark.css */
--image-filter: grayscale(50%);

img:not([src*='.svg']) {
  filter: var(--image-filter);
}

使用 JavaScript 自定义深色模式重新着色强度

每个人的情况不尽相同,并且人们对深色模式的需求也不同。 通过坚持上述重新着色方法, 我可以轻松地将灰度强度设置为用户偏好 通过 JavaScript 更改 通过将值设置为 0%,我还可以完全停用重新着色。 请注意,document.documentElement 提供对文档根元素的引用, 也就是说,我可以使用 :root CSS 伪类

const filter = 'grayscale(70%)';
document.documentElement.style.setProperty('--image-filter', value);

反转矢量图形和图标

对于矢量图形(在本例中用作我通过 <img> 元素引用的图标),我 使用不同的重新着色方法。 虽然研究表明 人们不喜欢将照片反转,但它确实适用于大多数图标。 我同样使用 CSS 变量来确定反转量 且处于 :hover 状态。

<ph type="x-smartling-placeholder">
</ph> 在深色模式下,图标会反转。 <ph type="x-smartling-placeholder">
</ph> 在深色模式下,图标会反转。
<ph type="x-smartling-placeholder">
</ph> 浅色模式下的常规图标。
浅色模式下的常规图标。

请注意,我再次只在 dark.css 中反转图标,而在 light.css 中不反转图标,以及 :hover 是如何反转的, 在两种情况下会获得不同的反转强度, 调暗或调亮一些,具体取决于用户选择的模式。

/* dark.css */
--icon-filter: invert(100%);
--icon-filter_hover: invert(40%);

img[src*='.svg'] {
  filter: var(--icon-filter);
}
/* light.css */
--icon-filter_hover: invert(60%);
/* style.css */
img[src*='.svg']:hover {
  filter: var(--icon-filter_hover);
}

currentColor 用于内嵌 SVG

对于内嵌 SVG 图片,不要使用反转滤镜, 您可以利用currentColor 表示元素的 color 属性值的 CSS 关键字。 这样,您就可以对默认情况下不会接收 color 值的属性使用该值。 很方便,如果将 currentColor 用作 SVG 的值 fillstroke 属性, 而是从 color 属性的继承值中获取值。 更棒的是,这也适用于 <svg><use href="…"></svg>、 这样你就可以有独立的资源 和 currentColor 仍将在上下文中应用。 请注意,这仅适用于内嵌<use href="…"> SVG, 而不是作为图片的 src 或通过 CSS 引用的 SVG。 如下面的演示所示,

<!-- Some inline SVG -->
<svg xmlns="http://www.w3.org/2000/svg"
    stroke="currentColor"
>
  […]
</svg>

在模式之间平滑过渡

事实上,在深色模式和浅色模式之间切换, colorbackground-color 均为 可动画化的 CSS 属性。 创建动画就像为这两个属性声明两个 transition 一样简单。 以下示例说明了总体思路,您可以在 演示

body {
  --duration: 0.5s;
  --timing: ease;

  color: var(--color);
  background-color: var(--background-color);

  transition: color var(--duration) var(--timing), background-color var(
        --duration
      ) var(--timing);
}

使用深色模式创作艺术指导

但一般来说,出于加载性能方面的原因,我建议仅使用 prefers-color-scheme<link> 元素的 media 属性中(而不是内嵌在样式表中), 在某些情况下,您可能需要直接内嵌在 HTML 代码中 prefers-color-scheme。 艺术指导就是这样一种情况。 在网页上,艺术指导关注的是网页的整体视觉外观及其视觉传达方式, 能够调动情绪、对比功能,并从心理上吸引目标受众群体。

使用深色模式时,将由设计师自己决定在特定模式下效果最佳的图片 以及图片重新着色是否不够好。 如果与 <picture> 元素一起使用,则要显示的图片的 <source> 可根据 media 属性进行设置。 在下面的示例中,针对深色模式显示西半球,针对浅色模式显示东半球 或者在没有指定偏好设置的情况下,在其他所有情况下均默认为东半球。 当然,这仅作说明之用。 在设备上开启/关闭深色模式即可查看差异。

<picture>
  <source srcset="western.webp" media="(prefers-color-scheme: dark)" />
  <source srcset="eastern.webp" media="(prefers-color-scheme: light)" />
  <img src="eastern.webp" />
</picture>

深色模式,但添加了停用选项

如上文为何要使用深色模式部分所述, 对于大多数用户来说,深色模式是一种美观的选择。 因此,有些用户可能更希望拥有自己的操作系统界面 但用户仍然更愿意按照自己惯用的方式浏览网页。 一种很好的模式是最初遵循浏览器发送的信号 prefers-color-scheme 权限,但之后可以选择允许用户覆盖其系统级设置。

<dark-mode-toggle> 自定义元素

当然,您可以自行创建代码 我为此而创建的现成自定义元素(网络组件)。 应用名为 <dark-mode-toggle> 并添加一个切换开关(深色模式:开/关)或 主题切换器(主题:浅色/深色),您可以对其进行充分自定义。 以下演示显示了该元素的实际运用 (哦,我也 🤫? 悄悄地把它 其他 样本 上文)。

<dark-mode-toggle
  legend="Theme Switcher"
  appearance="switch"
  dark="Dark"
  light="Light"
  remember="Remember this"
></dark-mode-toggle>
启用浅色模式的“dark-mode-toggle”
<dark-mode-toggle>(浅色模式)。
<ph type="x-smartling-placeholder">
</ph> 启用浅色模式的“dark-mode-toggle”
<dark-mode-toggle>(深色模式)。

在下面的演示中,尝试点击或点按右上角的深色模式控件。 如果您选中了第三个和第四个控件中的复选框, 。 这样,访问者就可以将操作系统保持在深色模式, 但用户却能在浅色模式下浏览网站,反之亦然。

总结

使用和支持深色模式很有趣,并开辟了新的设计新途径。 对于某些访问者来说,可能是无法处理您的网站 并为用户提供愉悦的体验 但肯定会遇到一些误区,需要进行仔细测试 但深色模式绝对是展现您对所有用户的关心的绝佳机会 本博文中提到的最佳实践以及 <dark-mode-toggle> 自定义元素 可以让您对自己打造令人惊叹的深色模式体验的能力充满信心。 请在 Twitter 上告诉我您创建了什么内容,以及此帖子是否有用 或改进建议 感谢阅读!🌒

适用于 prefers-color-scheme 媒体查询的资源:

有关 color-scheme 元标记和 CSS 属性的资源:

常规深色模式链接:

本博文的背景研究文章:

致谢

prefers-color-scheme 媒体功能(即 color-scheme CSS 属性) 和相关的元标记是 👏? Rune Lillesveen 的实现工作。 Rune 也是 CSS 颜色调整模块级别 1 规范的共同编辑器。 我想 🙏? 感谢 Lukasz ZbylutRowan MerewoodChirag Desai, 和 Rob Dodson ,了解他们对本文的全面审核。 加载策略Jake Archibald 的灵感来源。 Emilio Cobos Álvarez 指出了正确的 prefers-color-scheme 检测方法。 带有引用 SVG 和 currentColor 的提示来自 Timothy Hatcher。 最后,感谢各类用户调查的许多匿名参与者 这对本文中的建议起到了重要作用。 主打图片:Nathan Anderson