CSS变量需在:root定义并语义化命名,所有用色处必须显式调用var()且带安全回退值;JS切换主题应修改HTML属性而非仅setProperty;第三方库需确认其变量名与加载顺序。
直接在 :root 里定义变量就能统一主题色,但光写 --primary-color: #3b82f6 不会自动生效——所有用到颜色的地方,都得显式写 color: var(--primary-color),否则变量只是“存在”,没人“消费”。
浏览器只认 :root 下的变量为全局作用域;其他选择器(比如 .theme-dark)里定义的变量,只对后代生效,无法被顶层样式引用。
:root 是唯一能保证全页面可读的作用域起点,别用 html 或 body 替代--color-primary、--bg-surface,避免 --blue-500 这类具象命名:root 块里一次性写全,不能靠 JS 动态注入后再用变量未定义时,var(--text-primary) 不会继承或报错,而是直接 fallback 到 transparent 或父级继承值,导致文字消失、背景变白等 FOUC 现象。
color: var(--text-primary, #333),逗号后是纯 CSS 值,不能是另一个 var()
#333,背景用 #fff),不是随便填个 black
fill 和 stroke、伪元素 ::before 的 background-color 同样需要 var() + 回退值,极易遗漏document.documentElement.style.setProperty('--color-primary', '#1e40af') 只改内联 style,对 [data-theme="dark"] :root 这类规则无效——它不触发选择器匹配,变量值变了但样式没重绘。
document.documentElement.setAttribute('data-theme', 'dark'),让 CSS 规则自己接管html.theme-dark),就用 classList.toggle('theme-dark'),而非手动改变量Object.entries(theme).forEach(([k, v]) => el.style.setProperty(k, v)) 比连写十次 setProperty 更快,但仍不如属性切换稳定Tailwind、Bootstrap 5+、Ant Design 等虽支持 CSS 变量,但前提是它们内部真正在用——比如 Bootstrap 5.3 用的是 --bs-primary,不是 --primary-color;Tailwind 的 bg-primary 类只响应 tailwind.config.js 里配置的 colors.primary。
computed 样式,看 background-color 来源是否是 var(--bs-primary),而不是硬编码值:root 块之后加载,否则你的变量会被覆盖input:focus、button:active)、box-shadow 等常被忽略的位置,需单独补上 var()
真正难的不是“怎么定义变量”,而是确保每一处颜色都被 var() 覆盖、每一个回退值都经得起变量缺失考验、每一次 JS 切换都走对了 CSS 选择器路径——漏掉任何一个环节,主题就会局部失灵。