← 返回信息流
AI 资讯Hacker News·6 小时前

用Web标准实现深色模式

原标题:Dark Mode with Web Standards

速览

深色模式已成为现代应用的标准配置,但实现方式多样。本文讲解如何使用Web标准(如prefers-color-scheme媒体查询)检测用户系统主题,并动态切换样式。这种方法无需JavaScript,性能更优,且符合标准规范。它有助于提升用户体验并降低屏幕能耗。

AI 深度解读

背景

现代 Web 应用中,暗色模式(Dark Mode)已成为用户体验的核心需求之一。用户期望网站能够自动跟随操作系统的主题设置,同时也能在站点内部手动切换。然而,Web 标准在实现这一功能时存在一些技术细节和兼容性问题。这篇来自 Hacker News 的文章深入探讨了如何利用原生 CSS 和 HTML 标准(而非依赖 JavaScript 框架)来实现暗色模式,并指出了当前实现中的陷阱与未来方向。

核心内容

文章首先强调,尊重用户的操作系统设置是基础:只需在 CSS 中使用 prefers-color-scheme 媒体查询即可。但仅此还不够——用户应当能在每个站点上自定义自己的选择。例如,用户可能希望在应用程序的 UI 中使用暗色模式,但在内容密集的长文阅读网站上使用亮色模式。因此需要做到:首次访问时支持系统设置作为默认值,并在应用中提供一个切换开关,允许用户覆盖系统设置。

网页的颜色方案可以通过两种方式设置:在文档 <head> 中使用 HTML meta 标签 <meta name="color-scheme" content="light dark">,或者在 <html> 元素上设置 CSS 属性 color-scheme。由于慢速连接下 CSS 可能加载延迟,文章推荐使用 meta 标签的方式。首次访问时,<meta name="color-scheme" content="light dark"> 会尊重系统偏好。要覆盖系统设置,则使用 JavaScript 更新该 meta 标签的 content 属性值:light 强制亮色,dark 强制暗色,light dark 恢复为系统设置。示例代码中使用 localStorage 保存用户的选择,并在页面加载时恢复。

color-scheme 会影响什么?

  • 通过 CSS 函数 light-dark() 设置的色彩、渐变或图片。
  • 系统颜色,如 CanvasCanvasText
  • 滚动条颜色。
  • HTML 元素(如按钮)的默认颜色。
  • iframe 的样式(前提是 iframe 文档已通过 meta 标签选择启用)。
  • 使用了 light-dark()prefers-color-scheme 的 SVG。

color-scheme 不会影响什么?

color-schemeprefers-color-scheme 媒体查询之间存在不幸的脱节:prefers-color-scheme 反映的是操作系统设置,无论 color-scheme 的值如何。如果你在页面内提供了暗色模式的切换按钮,就不能直接采用 prefers-color-scheme 媒体查询来切换样式。例如,下面的 <picture> 元素不会受 color-scheme 影响:

<picture>
  <source srcset="logo-dark.png" media="(prefers-color-scheme: dark)" />
  <img src="logo-light.png" alt="Product logo" />
</picture>

除了使用 background-image,目前没有与 <picture> 元素等价的方法来引用 color-scheme 的值。

但有两个例外情形,color-scheme 会影响 prefers-color-scheme 媒体查询:iframesSVG。在 iframe 中,父文档的 color-scheme 样式可以覆盖子文档的媒体查询(前提是子文档已使用 prefers-color-scheme)。同样,在 SVG 内嵌的 <style> 中,prefers-color-scheme 也会受到包含该 SVG 的文档 color-scheme 的影响。文章给出了两个 iframe 和两个 SVG 示例,展示 color-scheme: lightcolor-scheme: dark 下的不同表现。

CSS 规范最近已更新,使文档的 color-scheme 在所有上下文中都能影响媒体查询,但目前还没有浏览器实现这一变更。

Safari 的注意事项

  • SVG 内支持 prefers-color-scheme 媒体查询是在 Safari 27 中添加的,但 color-scheme 不会影响该媒体查询(存在 bug)。
  • iframe 内支持 prefers-color-scheme 媒体查询也是在 Safari 27 中添加的,父文档的 color-scheme 会正确覆盖它(🎉)。然而,仍存在其他 bug。

使用 light-dark() 处理图片与渐变

最初 light-dark() 函数仅限用于颜色。现在它也可以用于渐变色和图片(Chrome/Edge 150 版本、Firefox 150 版本、Safari Technology Preview 已支持)。示例:

.bg-gradient {
  background-image: light-dark(linear-gradient(15deg, #b9b6ff, #308dc6), linear-gradient(15deg, #6b7495, #001339));
}

甚至可以实现在纯色和渐变之间切换:

.bg-grad-solid {
  background-image: light-dark(linear-gradient(15deg, #b9b6ff, #308dc6), image(#001339));
}

图片切换:

.bg {
  background-image: light-dark(url(/lightmode.avif), url(/darkmode.avif));
}

改变颜色、图片和渐变之外的内容

大多数情况下,暗色模式仅需改变色彩,但也有例外:例如,一个 box-shadow 在暗色背景上可能不可见,此时可能需要改用 border。实现这样的切换目前较为困难。CSS 标准组织正计划通过 if() 语句或样式查询(style query)来检测当前颜色方案,但尚无浏览器实现。文章提出了两种当前可行的替代方案:

  1. 定义一个 CSS 自定义属性 --dark 来表示是否处于暗色模式,然后利用样式查询(style queries)根据该属性值应用不同样式。例如,构建 html:has([content="light dark"]) 配合 prefers-color-scheme: dark 来设置 --dark: true,或者直接检测 content="dark"。然后使用 @container style(--dark: false)@container style(--dark: true) 来切换 box-shadowborder

  2. 更优雅的方式:使用 @property 注册一个自定义属性 --usedScheme,将其初始值设为 transparent,然后在 body 上通过 light-dark(white, black) 设定其值。之后通过样式查询检测该属性的实际值(例如 white 表示亮色,black 表示暗色),从而应用不同的样式规则。

未来的可能:通过 JavaScript 覆盖 prefers-color-scheme

未来我们或许能通过 JavaScript 直接覆盖 prefers-color-scheme 媒体查询。已有规范草案、MDN 条目以及 Chrome Canary 的原型,但 Safari 团队反对这个想法。

关键要点

  • 基础实现:使用 <meta name="color-scheme" content="light dark"> 尊重系统设置,并配合 JavaScript 与 localStorage 提供用户覆盖。
  • color-schemeprefers-color-scheme 存在脱节:页面内的暗色切换按钮不能依赖 prefers-color-scheme 媒体查询,因为该查询始终反映 OS 设置。
  • 例外情形:在 iframe 和 SVG 中,父文档的 color-scheme 可以影响子文档的 prefers-color-scheme 媒体查询。这是当前浏览器实现的特例。
  • Safari 在 SVG 和 iframe 中支持 prefers-color-scheme 但存在 bug:SVG 内 color-scheme 不影响媒体查询;iframe 中覆盖正常但仍有其他问题。
  • light-dark() 函数已可用于渐变和图片(Chrome 150+、Firefox 150+、Safari TP),实现图片/渐变在亮暗模式间的自动切换。
  • 对于非颜色属性的切换(如 box-shadow 改为 border),当前可通过 style queries + 自定义属性(如 --dark--usedScheme)实现变通方案。
  • 未来可能通过 JavaScript 直接覆盖 prefers-color-scheme 媒体查询,但浏览器阵营意见不统一(
查看原文 →olliewilliams.xyz