很多人做深色模式的做法是:把白色换成黑色,把黑色换成白色,完成。 结果打开一看,界面刺眼、层次糊在一起、原本漂亮的插图变得脏兮兮的。
常见错误:纯黑背景 + 纯白文字
#000000 配 #ffffff 的对比度高达 21:1,
在暗环境下阅读会产生明显的光晕感,长时间看非常累。
专业的深色界面几乎不会使用纯黑,而是用带一点色调的深灰。
/* 推荐:带一点冷调的深灰,而不是纯黑 */
:root {
--bg: #f7f7f5; /* 浅色模式背景 */
--text: #1b1c1e;
}
[data-theme="dark"] {
--bg: #121417; /* 深色模式背景:略微偏蓝 */
--text: #ecedee; /* 不用纯白,降低眩光 */
}
层级要反过来想
浅色模式里,越「高」的元素越白,靠阴影制造悬浮感。 深色模式中抬升的元素应该稍亮,同时减少阴影 —— 因为深色背景上的阴影几乎看不见。
浅色靠阴影表达层级,深色靠亮度表达层级。
文字对比度的三个档位
| 用途 | 建议对比度 | 说明 |
|---|---|---|
| 正文 | 10:1 ~ 14:1 | 不用拉满,留一点呼吸感 |
| 次要信息 | 6:1 ~ 8:1 | 时间、标签、说明文字 |
| 禁用状态 | 3:1 左右 | 保持可辨识但明显弱化 |
强调色需要重新调
同一支品牌色在浅色背景上很好看,放到深色背景上往往会显得沉闷。 解决办法是提高亮度、降低饱和度。
[data-theme="dark"] {
--accent: #6fc5b8; /* 比浅色模式更亮、更柔 */
}
/* 用变量统一管理,切换时整体跟随变化 */
实现要点
- 所有颜色都走 CSS 变量,切换时只改变量,不动组件样式。
- 在
<head>里用一段极短的脚本先读取用户偏好,避免页面闪白。 - 提供手动切换按钮,并把选择存进
localStorage。 - 尊重系统的
prefers-color-scheme,这也是用户的默认预期。 - 不只在颜色上做区分,标签、边框、禁用态都要检查一遍。
<script>
// 放在 <head> 中,防止主题闪烁
(function () {
var saved = localStorage.getItem("theme");
var prefersDark = matchMedia("(prefers-color-scheme: dark)").matches;
document.documentElement.dataset.theme = saved || (prefersDark ? "dark" : "light");
})();
</script>
上线前的自查清单
- 背景不是纯黑,正文不是纯白。
- 卡片、弹窗、输入框在深色下边界清晰。
- 图片与插图的透明区域不会穿帮。
- 代码块、表格、引用块都有合适的深色配色。
- 切换主题后刷新页面,设置依然保留。
深色模式本质上是一套独立的设计方案,而不是一次颜色替换。 把它当成重新设计一遍,结果会好得多。