CSS变量需声明在:root或带class的根元素内才生效,单独声明无效;推荐用classList控制主题类名并配合localStorage持久化,且初始化脚本须置于head中同步执行以防闪屏;同时设置color-scheme确保原生控件适配主题。

CSS变量必须声明在:root或带class的根元素内部才生效
直接写--color-bg: #1a1a1a会无效,浏览器不认。变量得挂载到:root或html.theme-dark这类选择器下,靠继承机制向下透传。常见错误是把变量单独拎出来写在CSS文件开头,结果整个页面都用不到。
推荐结构:
:root {
--color-bg: #fff;
--color-text: #333;
}
.theme-dark {
--color-bg: #1a1a1a;
--color-text: #eee;
}
这样document.documentElement.classList.toggle('theme-dark')一执行,所有var(--color-bg)就自动切换了,不用挨个改style.setProperty。
立即学习“前端免费学习笔记(深入)”;
用classList.toggle而不是style.setProperty批量设变量
硬编码root.style.setProperty('--color-bg', '#1a1a1a')看似直接,但变量一多就失控:漏设、拼错名、回退难、无法利用CSS过渡动画。更糟的是,它绕过了CSS层的级联逻辑,@media (prefers-color-scheme: dark)这类媒体查询也失效。
可靠做法是只用JS控制类名:
-
document.documentElement.classList.add('theme-dark')(单向启用) -
document.documentElement.classList.remove('theme-light')(单向清除) -
document.documentElement.classList.toggle('theme-dark')(开关式)
localStorage读取必须在DOM渲染前完成,否则闪屏
如果等DOMContentLoaded再读localStorage.getItem('theme')并加class,用户会先看到默认主题(比如白底),0.1秒后才切到深色——这就是“闪屏”。解决办法只有两个:
- 把初始化脚本放在
里,且不加defer或async(同步执行) - 用
document.write('')在HTML开头注入(极简场景)
同时别忘了监听切换事件时立刻存localStorage.setItem('theme', 'theme-dark'),否则刷新就丢配置。
别忽略color-scheme: light dark对原生控件的影响
即使你把input、checkbox、select全样式重写了,浏览器仍可能按系统偏好渲染它们的默认焦点框、滚动条颜色。加一句:root { color-scheme: light dark; }能强制让这些控件适配当前主题,这是2026年主流浏览器(Chrome/Firefox/Safari)都支持的标准行为,但容易被跳过。


















