css自定义属性全局变量必须在:root中以--开头声明,作用域覆盖全部后代,仅通过js的style.setproperty()可动态更新,拼写错误或提前引用会导致静默失效。

在 :root 里声明 CSS 自定义属性就是定义全局变量
浏览器把 :root 当作文档最高层的元素(等价于 html),所有在它里面用 -- 开头声明的属性,都会被注入到整个 CSS 作用域中,后续任意选择器都能通过 var(--xxx) 访问。这不是“模拟”全局变量,是原生支持的真全局。
- 必须以两个短横线
--开头,比如--primary-color,否则不被识别为自定义属性 - 声明位置不一定要写在
:root最顶层;只要在:root块内,哪怕嵌套在媒体查询或条件规则里,也属于全局作用域 - 不能在内联样式(
)里声明--xxx并指望它变成全局变量——内联声明只对当前元素生效
为什么不能在 body 或普通类里声明全局变量
因为 CSS 自定义属性的作用域是“继承+级联”,不是“命名空间”。在 body 里声明 --color,子元素能读到,但 html 自身、同级的 head 里的样式、或者通过 @import 加载的外部 CSS 都无法访问它。只有 :root 是唯一能覆盖全部后代且不被其他选择器遮蔽的锚点。
-
html { --x: red; }和:root { --x: red; }效果一样,但:root更明确、更常用,且兼容性略好(IE 不支持,但没人会在意) - 如果在
.theme-dark { --bg: #111; }里声明,那这个--bg只对.theme-dark及其后代有效,不是全局 - 多个
:root块会合并,后声明的同名变量会覆盖前面的,类似 CSS 级联规则
var(--name) 读取失败的常见原因
报错不明显,往往只是值没生效,颜色/尺寸回退到初始值。问题通常不在语法,而在作用域或拼写。
- 拼写大小写敏感:
--MainColor和--maincolor是两个变量 - 引用时名字写错,比如声明了
--spacing-m,却写了var(--spacing-s),此时会直接使用属性默认值(如margin就是0),控制台也不报错 - 在未声明变量的上下文中提前使用,例如在
:root声明之前就有一个div { color: var(--text); }—— 这时var()无效,浏览器忽略该声明 -
var()不能用于@keyframes的关键帧内部作为动画属性值(部分浏览器限制),也不能直接用在@media查询条件中
动态更新 :root 变量要靠 JavaScript
CSS 本身没有“重新赋值”语法,所有修改都得走 JS 的 style.setProperty()。这是最常被忽略的一环:很多人以为改了 CSS 文件里的 :root 就能热更新,其实不行。
立即学习“前端免费学习笔记(深入)”;
- 正确做法:
document.documentElement.style.setProperty('--primary', '#007bff'); - 批量更新建议封装函数,避免重复写
document.documentElement.style - 注意单位:JS 设置时如果漏掉单位(如把
'16'当成px),CSS 不会自动补,会导致计算失败(font-size: var(--size)若--size是'16',实际是font-size: 16;,非法) - 服务端渲染或构建时替换变量?那得用 PostCSS 或构建插件,纯 CSS 不支持










