⭐ 推荐:社区规则条款 V1.0

深色模式适配:prefers-color-scheme 与颜色设计体系

一只冷漠的狐狸
一只冷漠的狐狸 正式会员正式会员认证极客认证极客 钻石卡会员钻石卡会员
发布于 2026-07-31 20:21 ·86 浏览 ·0 回复
内容摘要

深色模式适配应把颜色抽为 CSS 变量或语义令牌,以 prefers-color-scheme 自动跟随系统、data-theme 支持手动切换,按三层令牌管理颜色,深色下用低对比背景、非纯白文字和表面亮度分层而非简单反色。

深色模式适配最省事的做法不是再写一套样式表,而是把颜色抽成 CSS 变量(设计令牌),用 prefers-color-scheme 媒体查询让页面自动跟随系统,再用 data-theme 属性给用户留一个手动切换的口子——一套 CSS,两种外观。

结论:媒体查询负责"自动",CSS 变量负责"可换肤"

prefers-color-scheme 是 CSS 媒体特性,用来读取操作系统当前是浅色还是深色偏好,取值有 light、dark、no-preference 三种,现代浏览器全部支持。它的职责只有一件事:告诉你用户偏好什么。

真正让颜色能整体翻转的是 CSS 自定义属性(变量)。把组件里写死的 #333、#fff 全部替换成语义变量后,切换主题就变成"换一组变量值",而不是去改几十个选择器。

结论:深色模式 = prefers-color-scheme 做默认判断 + :root 变量做主题载体 + data-theme 属性做用户覆盖,三者缺一不可。

:root{
  color-scheme: light dark;      /* 让滚动条、表单控件跟随主题 */
  --c-bg:#ffffff;
  --c-fg:#1a1a1a;
  --c-muted:#6b7280;
  --c-border:#e5e7eb;
  --c-brand:#2563eb;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --c-bg:#121212;
    --c-fg:#e6e6e6;
    --c-muted:#9ca3af;
    --c-border:#2a2a2a;
    --c-brand:#60a5fa;
  }
}
:root[data-theme="dark"]{ /* 手动切深色,内容与上面一致 */ }

注意 color-scheme 这个属性,很多人漏掉它,结果深色页面上输入框还是刺眼的白底。

颜色设计体系:三层令牌,别在组件里写色号

结论:颜色变量分三层——原始色板、语义令牌、组件变量——组件只允许引用语义层。

  • 原始色板:--blue-500:#2563eb,只作为"调色盘",不直接用于组件。
  • 语义令牌:--c-bg、--c-fg、--c-surface、--c-border、--c-brand、--c-danger,描述用途而非颜色本身。
  • 组件变量:需要时再包一层,如 --btn-bg: var(--c-brand)。

这样做的收益是深色模式只需要维护一份"语义映射表"。如果组件里写的是 --blue-500,深色下想把蓝色调亮就得全局搜索替换。

深色模式不是"颜色取反",这几个参数要记牢

结论:深色主题的正确姿势是"低对比背景 + 不那么白的文字 + 靠表面亮度分层",直接 invert(1) 是灾难。

  • 背景别用纯黑 #000,用 #121212 或 #1a1a1a,纯黑配白字会产生光晕感,长时间阅读眼睛累。
  • 正文文字别用纯白 #fff,用 #e6e6e6 左右,正文对比度控制在 4.5:1 以上(WCAG AA 标准),大字可放宽到 3:1。
  • 层级用"表面叠加"表达:卡片在背景上抬升一级,通过把背景色亮度提高 2%~5% 实现,例如 #121212 → #1e1e1e → #232323。深色下 box-shadow 几乎不可见,改用 1px 描边或提亮表面更可靠。
  • 品牌色深色下要降饱和、提亮度,把 #2563eb 换成 #60a5fa 这类。饱和度过高的色块在深底上会"发光"。
  • 图片和插画:透明底 PNG、纯黑线条 SVG 在深色下常常糊掉。SVG 用 currentColor 填充可自动跟随;照片可用 <picture> 配合 media="(prefers-color-scheme: dark)" 换图,别滥用 filter: brightness()。

切换按钮怎么写才不闪白

结论:主题判断要在 <head> 里的内联脚本中同步执行,绝不能等 DOMContentLoaded。

优先级是:用户手动选择 > 系统偏好 > 默认浅色。把这段脚本放在 <head> 最靠前的位置:

<script>
(function(){
  var t = localStorage.getItem('theme');
  if(!t) t = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
  document.documentElement.dataset.theme = t;
})();
</script>

用户点击切换时,写入 localStorage 并同步更新 document.documentElement.dataset.theme;另外记得监听 matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ...),这样用户在系统里切主题、还没手动选过时,页面能实时跟着变。移动端的 <meta name="theme-color"> 也要按主题给两个值,否则浏览器地址栏颜色会突兀。

落到无构建体系的模板上

结论:深色适配不需要任何打包工具,纯 CSS 变量 + 一小段内联 JS 就能完成。

如果你要给自己的 Clara BBS 模板加深色模式,正好合适:它是一套模板同时适配手机与桌面的响应式结构,颜色统一走 CSS 变量后两种外观共用同一套视图,不需要维护两套模板;系统本身无编译缓存、不需要 Composer 和命令行,改动就落在模板 CSS 与 <head> 里那段内联脚本上,保存刷新即可看到效果。别引入 Sass 变量编译或 Tailwind 的 dark: 方案,那会平白多一层构建负担。

收个尾:深色模式的工程难点从来不在"怎么变黑",而在颜色有没有被抽象成令牌。先把语义变量立起来,prefers-color-scheme 只是最后那行媒体查询;再记住背景不用纯黑、文字不用纯白、层级靠表面亮度、对比度守住 4.5:1,适配就基本不会翻车。

本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-441.html
转载请注明出处,版权归原作者所有。

全部回复 0

还没有回复,来抢沙发~