:root是唯一符合规范的全局css变量挂载点,因跨文档兼容、层叠优先且位于继承链顶端;html或body声明会导致作用域残缺、覆盖风险或静默失效。

必须在 :root 里定义,否则就不是全局的——写在任何 class、tag 或媒体查询外层之外的 :root 块以外的位置,变量作用域都会被截断。
为什么只能用 :root,不能用 html 或 body
:root 是 CSS 规范中唯一保证最高优先级且全文档可继承的作用域。虽然它等价于 html 元素,但优先级略高;而 html 选择器本身不带这个语义保障,body 更是完全错误——写成 body { --color-primary: #007bff; },变量只对 body 及其子元素生效,但无法被 :root 下其他同级节点(比如 head 中的 style)访问,JS 也读不到。
-
:root是伪类,代表“文档根”,浏览器强制将其视为顶层作用域 -
html是元素选择器,受样式层叠影响,可能被其他规则覆盖 -
body完全没资格——它连根都不是,变量根本不会冒泡到 document.documentElement
--color-primary 这类命名到底该怎么定
变量名必须语义化,直接反映用途而非视觉值。写成 --blue-500 或 --main-btn-bg 都是自找麻烦:前者绑定设计系统色号,换一套蓝系就得全量重命名;后者绑定组件,将来 .card 也要用主色时就得复制或改名。
- 推荐前缀统一为
--color-+ 角色/状态,如--color-primary、--color-text-inverse、--color-border-disabled - 避免大小写混用:
--Color-Primary和--color-primary是两个变量 - 不要用数字结尾(如
--color-1),后期无法解释含义,CI 校验也难加语义规则
var() 不设 fallback 值会出什么问题
不写回退值,遇到变量未定义、拼写错误、或 JS 动态设置失败时,属性会直接失效——比如 color: var(--color-text); 在变量不存在时,浏览器按规范会把 color 设为 inherit,结果文字突然看不见;background-color 则可能变成透明,露出底层内容。
- 所有
var()必须带 fallback,格式为var(--color-text, #333) - fallback 值要是合法 CSS 值,不能是另一个
var()(嵌套 fallback 不被支持) - IE 不支持 CSS 变量,fallback 就是它的实际颜色值,别偷懒写成
var(--x, initial)
动态更新时为什么 setProperty 要调用 document.documentElement
document.documentElement 对应的就是 :root 所代表的节点。只有往它身上写,才能触发全页面变量重计算和样式重绘。写成 document.body.style.setProperty 或随便找一个元素调用,变量只在那个局部生效,其他地方完全无感。
- 正确写法:
document.documentElement.style.setProperty('--color-primary', '#0d6efd'); - 批量更新建议用
Object.entries(theme).forEach(([k, v]) => ...),避免多次重排 - 注意:变量值变更后,依赖它的 CSS 属性会自动重绘,无需手动
forceLayout或reflow
真正容易被忽略的不是怎么写,而是谁来维护这些变量——如果设计系统 token 存在 tokens/colors.json 里,CSS 变量却靠人手同步,半年后必然脱节。可靠的做法是让构建脚本从 JSON 生成 :root 块,并加入 CI 检查变量名是否全部覆盖、是否有未使用的冗余项。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











