很多团队把暗黑模式当成一个“以后再补”的视觉需求,直到产品规模变大才发现,它影响的不只是颜色,而是整个系统的稳定性:组件状态、图标资源、内容图片、代码高亮、甚至品牌气质都会被牵动。
所以主题切换与暗黑模式更适合作为产品一致性策略来设计,而不是末期补一套配色。
先决定主题系统的边界,而不是先改颜色
主题系统通常至少涉及四层:
- 设计令牌层:颜色、阴影、边框、语义状态
- 组件层:按钮、表单、卡片、导航等视觉状态
- 页面层:背景层级、分区关系、内容可读性
- 系统层:跟随用户系统偏好、持久化设置、首屏闪烁控制
如果只在页面层直接改颜色值,后续维护会非常痛苦。更稳的做法,是让主题切换优先围绕 design token 展开。
:root {
--bg-page: #ffffff;
--bg-surface: #f6f7fb;
--text-primary: #111827;
--border-muted: #d1d5db;
}
[data-theme='dark'] {
--bg-page: #0f172a;
--bg-surface: #111827;
--text-primary: #f8fafc;
--border-muted: #334155;
}
暗黑模式的核心不是反色,而是重建层级关系
许多失败的暗黑模式并不是颜色选错,而是直接把浅色主题反过来用,结果页面层级消失、重点不清楚、阅读压力更大。
真正有效的暗色方案通常会重新处理:
- 页面和卡片的层级落差
- 主按钮与次按钮的对比方式
- 文本与辅助信息的亮度差
- 数据图表与图像素材的夜间表现
用户开启暗黑模式,并不是只想“变黑”,而是希望在低光环境里仍然容易阅读和操作。
主题切换必须控制首屏一致性和状态持久化
很多产品已经有暗黑模式,但切换体验依然很差,原因在于:
- 首屏先闪浅色再切深色
- 页面切换时主题状态丢失
- SSR 输出与客户端主题不一致
更稳的做法,是在最早阶段就决定主题来源优先级:系统偏好、用户显式选择、默认主题。
const THEME_KEY = 'site-theme'
export function resolveTheme(): 'light' | 'dark' {
const stored = localStorage.getItem(THEME_KEY)
if (stored === 'light' || stored === 'dark') return stored
return window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light'
}
AI 可以帮助做主题扫描,但不能替代主题策略
AI 很适合协助团队做几件事:
- 扫描 token 是否被硬编码覆盖
- 查找组件状态在不同主题下的缺口
- 发现图标、插图、代码块等非文本资源的不一致
但它不能替代关键判断:品牌是否适合强暗色、哪些界面应保持高亮、哪些业务场景暗黑模式会降低识别效率。主题策略最终仍然属于产品和设计决策。
一个常见失败案例:有主题切换按钮,但体验并不可信
这类问题通常有几个信号:
- 页面主色切了,组件状态没切
- 暗色下边框和分隔信息几乎看不见
- 图表、插图、截图仍然是浅色世界
- 首屏和路由切换存在闪烁
这说明团队做的是“视觉补丁”,不是“主题系统”。
一份可直接复用的检查清单
- 主题切换是否基于 design token,而不是页面散落颜色值
- 暗黑模式是否重新设计了层级关系,而不是简单反色
- 系统偏好、用户选择和 SSR 首屏是否有明确优先级规则
- 组件状态、图表、插图和代码块是否都覆盖了主题差异
- AI 检测是否被用于发现缺口,而不是替代主题策略判断
总结
主题切换与暗黑模式真正重要的,不是“提供一个开关”,而是让产品在不同光照和偏好下仍然保持一致、可信和可读。只要先把 token 体系、层级关系和首屏策略设计清楚,暗黑模式就会成为系统能力,而不是维护负担。
进一步阅读:


