配了三年暗色模式,今天发现第三态根本没人用——两个状态就够了
大多数网站的暗色模式开关都有三个选项:浅色、深色、系统。看起来很合理——系统是一个「策略」,另外两个是「值」,用户应该都能选到。
但这个逻辑是错的。
Lea Verou 前几天专门写了一篇博客来说这件事。她的核心论点是:三态暴露的是实现模型,不是用户目标。用户在网站上找不到暗色模式开关时只有一个理由:页面看着不舒服,要改。找到一个「系统」选项、搞清楚它和「浅色」「深色」的区别、然后意识到「我其实只是想让它别这么亮」——这套认知成本,解决的是一个几乎不存在的问题。
Tri-state toggles solve an imaginary problem that barely exists in practice. Most users never seek out the toggle unless something is actually wrong with the current view.
三个状态的代价是真实的:下拉菜单比单图标多一步点击,三列并排比两列多占一倍的屏幕空间。更糟糕的是,它强迫用户在「看起来完全一样」的选项之间做选择,违反了可用性里的反馈原则——你选了某个选项,页面看起来没有任何变化。
现在主流网站开始转向两个状态了。Material Design、Radix、ShadCN 都是。浏览器支持也早就到位了。
color-scheme 从 2022 年就是 Baseline,light-dark() 函数现在所有主流浏览器都支持。这两个 API 组合起来,让「两个状态」的实现比「三个状态」还简单。
color-scheme 告诉浏览器页面支持哪种配色方案,同时控制浏览器自带的滚动条、表单控件等原生 UI 的颜色。light-dark(value-for-light, value-for-dark) 根据当前启用的配色方案,自动返回对应的值。
第一步,HTML 里放一个按钮。
<button id="theme-toggle" aria-label="切换暗色模式">
<span class="icon-sun">☀️</span>
<span class="icon-moon">🌙</span>
</button>
第二步,CSS 把 color-scheme 和 light-dark() 配合起来用。
:root[data-theme="dark"] {
color-scheme: dark;
}
:root[data-theme="light"] {
color-scheme: light;
}
body {
background: light-dark(#ffffff, #1a1a1a);
color: light-dark(#1a1a1a, #f5f5f5);
}
第三步,JavaScript 读取系统偏好,然后管理用户的切换。
const stored = localStorage.getItem("theme");
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const theme = stored || (prefersDark ? "dark" : "light");
document.documentElement.dataset.theme = theme;
document.getElementById("theme-toggle").addEventListener("click", () => {
const next = document.documentElement.dataset.theme === "dark" ? "light" : "dark";
document.documentElement.dataset.theme = next;
localStorage.setItem("theme", next);
});
color-scheme 和 @media (prefers-color-scheme) 的区别在这里很关键。@media 只读操作系统的设置,但 color-scheme 会覆盖浏览器的「自动暗色模式」——Chrome 从某个版本开始会自动把没有声明 color-scheme 的页面转成暗色,但如果页面自己声明了 color-scheme,就不会被浏览器强转。
第一次加载时,用户没有手动选择过,JavaScript 会自动读取 prefers-color-scheme。用户选了「暗色」,color-scheme: dark 生效,light-dark() 就返回暗色的值。light-dark() 自动跟着 color-scheme 走,不需要额外的 @media 查询。UI 按钮只需要两个图标:浅色时显示月亮(点一下切到暗色),暗色时显示太阳(点一下切到浅色)。
如果用户从来没碰过开关,就保持系统偏好。
Lea Verou 在博客里提到了一个细节:设置面板里放三个状态是合理的,因为用户是主动去找的,目的本身就是改设置。但在页面顶部的那个开关,两个状态够了。这背后的本质是:数据模型需要三个状态(浅色、深色、系统),但 UI 只需要两个选项来表达这三个状态——「浅色」和「暗色」都覆盖了「系统」的逻辑,因为用户不点开关就默认跟着系统走,点了就是在 Override 系统偏好。
现在可以动手试了。
评论区
登录后可评论。