深色模式不能只靠class切换,因会导致样式失控;应使用CSS变量集中管理主题值,并通过:root声明默认值、@media和data-theme覆盖以确保可维护性与兼容性。

深色模式切换为什么不能只靠 class 切换?
单纯给 body 加 class="dark" 再写一堆 .dark .btn { color: #fff; } 会快速失控:颜色值重复、状态组合爆炸(比如 .dark .btn:hover、.dark .btn:disabled)、主题变量无法复用。CSS 变量能集中管理这些值,且支持动态更新,是真正可维护的解法。
定义和使用 CSS 变量的最小可行结构
必须在 :root 里声明默认值,并在 dark 模式下覆盖——否则 JS 切换时变量未定义会导致回退到浏览器默认色(比如黑色文字配黑色背景)。
:root {
--text-primary: #333;
--bg-surface: #fff;
--border-color: #e0e0e0;
}
<p>@media (prefers-color-scheme: dark) {
:root {
--text-primary: #eee;
--bg-surface: #1a1a1a;
--border-color: #333;
}
}</p><p>body {
color: var(--text-primary);
background-color: var(--bg-surface);
border-color: var(--border-color);
}</p>
-
:root是全局作用域,确保所有元素都能访问 - 不要漏掉
@media (prefers-color-scheme: dark),它让系统级深色偏好自动生效 - 变量名用
--开头,命名建议语义化(如--text-primary而非--color-1)
用 JavaScript 主动切换主题并持久化
用户点击按钮切换时,不能只改 class,必须同步更新 CSS 变量或触发媒体查询匹配。最稳妥的方式是给 html 元素加 data-theme="dark",再用 CSS 覆盖变量。
document.documentElement.setAttribute('data-theme', 'dark');
对应 CSS:
[data-theme='dark'] {
--text-primary: #eee;
--bg-surface: #1a1a1a;
--border-color: #333;
}
- 优先读取
localStorage恢复上次选择:localStorage.getItem('theme') - 切换时同时写入
localStorage和设置data-theme属性 - 避免直接操作
style.setProperty()—— 多个变量要逐个设,易遗漏;用属性控制更可靠 - 注意:如果用户系统是深色模式,但手动切回浅色,需显式清除
data-theme或设为light,否则媒体查询会被属性覆盖
为什么 calc() 和 var() 组合容易出错?
想用 CSS 变量做颜色混合或明度调整?别直接 color: calc(var(--text-primary) * 0.8) —— calc() 不支持颜色运算,会直接失效。
- 颜色计算必须用
hsl()或color-mix()(后者兼容性差) - 例如调暗文字:
color: hsl(0, 0%, calc(100% - 20%));配合变量:--text-lightness: 30%;→color: hsl(0, 0%, calc(100% - var(--text-lightness))); - 透明度用
rgba()+var()数字:定义--alpha: 0.8;,然后background-color: rgba(0, 0, 0, var(--alpha)); - 所有非数值变量(如颜色字符串)不能参与
calc(),会整个声明被浏览器忽略
变量本身不“智能”,它只是字符串替换。深色模式的健壮性,取决于你是否把所有可变值都收进变量、是否覆盖了所有必要上下文、以及是否处理了系统偏好与用户手动选择的优先级冲突。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











