变量必须定义在 :root 才能全局生效,所有主题色变量(如 --color-primary)须写在 :root 选择器内;var() 必须带 fallback 值;深色模式推荐用 HSL 拆解控制;JS 切换主题须用 style.setProperty()。

变量必须定义在 :root 才能全局生效
所有主题色变量(如 --color-primary)必须写在 :root 选择器里,不能写在 .theme-dark 或组件类中。因为只有 :root 等价于 html 元素,是整个文档的继承根——var(--color-primary) 才能在 ::before、svg、伪类等任意位置正确取值。
常见错误包括:
- 把变量写在
.dark-mode { --bg: #111; }里,结果子元素读不到 - 漏掉双短横线,写成
primary-color,浏览器直接忽略该声明 - 大小写不一致:
--PrimaryColor和--primarycolor是两个不同变量
正确写法示例:
:root {
--color-primary: #007bff;
--color-bg: #ffffff;
--color-text: #333333;
}
var() 必须带 fallback 值,否则容易“失色”
var() 不校验变量是否存在,也不报错。如果 --color-bg 没定义,又没写 fallback,background-color: var(--color-bg) 会回退到 transparent 或 inherit,页面可能突然变白、变黑或文字消失。
立即学习“前端免费学习笔记(深入)”;
安全写法始终带第二个参数:
color: var(--text-default, #333);border-color: var(--border-subtle, #e0e0e0);- fallback 值建议用语义明确的默认色,别用
initial或空字符串
注意:fallback 只在变量未定义或为空时触发,不是浏览器兼容降级方案。
深色模式切换别只改颜色值,用 HSL 拆解更可控
直接替换十六进制值(比如把 #4a90e2 改成 #1e3a5f)会导致悬停、禁用、文字灰度全部脱节,视觉跳变明显。
推荐把主色拆成三个变量:
-
--primary-h: 210;(色相,无单位) -
--primary-s: 65%;(饱和度,带 %) -
--primary-l: 57%;(明度,带 %)
然后用 hsl() 动态组合:
button {
background: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
}
button:hover {
background: hsl(var(--primary-h), var(--primary-s), calc(var(--primary-l) - 8%));
}切换深色模式时,只需调低 --primary-l,色相和饱和度保持不变,观感才稳定。
JS 切换主题必须用 style.setProperty(),别碰 cssText
修改变量值的唯一安全方式是:
document.documentElement.style.setProperty('--color-bg', '#1a1a1a');绝对不要写:
-
document.documentElement.style.cssText = '--color-bg: #1a1a1a';(会清空已有内联样式) -
document.documentElement.setAttribute('style', '--color-bg: #1a1a1a');(覆盖整个 style 属性)
其他关键点:
- 确保变量已在 CSS 中预先声明,否则 JS 设置后仍 fallback
- 用
data-theme控制主题比 class 更稳妥,避免权重冲突 - 首次加载需从
localStorage读取偏好,并在DOMContentLoaded后立即应用,防闪屏
真正麻烦的从来不是怎么切,而是变量定义位置错了、fallback 漏了、HSL 单位写成字符串,或者 JS 调用时机早于 DOM 就绪——这些地方一错,整套主题就断层。


















