全局CSS变量必须定义在:root中才能被所有组件继承,否则在Shadow DOM、scoped样式或深层嵌套中失效;变量名以--开头,var()必须带fallback,伪类中应覆盖变量而非硬编码颜色,currentColor可实现动态颜色同步。

变量必须在 :root 中定义,否则组件读不到
全局颜色复用的前提是变量能被所有组件继承。只写 html 或 body 里声明 --primary,在 Shadow DOM、某些框架(如 Vue 的 scoped style)或嵌套深的组件中会失效。:root 是 CSS 规范指定的根作用域,浏览器保证其后代无条件继承——这是唯一稳妥的位置。
常见错误:把变量塞进某个组件的 wrapper 类里,比如 .dashboard { --bg: #f9fafb; },结果 .sidebar 根本取不到这个值。除非 sidebar 是 dashboard 的直系后代,且你显式写了 .sidebar { background-color: var(--bg); },否则它连变量名都看不到。
- 变量名必须以
--开头,例如--theme-primary,不能省略 - 值推荐用十六进制或
hsl(),避免用命名色(如blue),JS 无法读取计算 - 别在
:root里混写带单位的数值(如--spacing: 8px)和颜色,语义混乱易误用
var() 必须带 fallback,否则样式直接挂掉
color: var(--primary) 看似简洁,但一旦 --primary 未定义、拼错(--primay)、或被更高优先级规则覆盖,整个声明会被浏览器忽略,元素可能变成默认黑色或透明——页面“破相”往往就在这儿。
fallback 不是默认值,而是兜底安全网:color: var(--primary, #3b82f6)。第二个参数只能是静态值,不支持嵌套 var()、表达式或函数。
立即学习“前端免费学习笔记(深入)”;
- 所有用到
var()的地方都得加 fallback,包括background-color、border-color、box-shadow - 伪类里也一样:
.btn:hover { background-color: var(--btn-bg-hover, #0056b3); } - fallback 值建议和设计系统主色一致,避免视觉跳变
状态色别硬写四遍,用变量覆盖更可控
按钮的 :hover、:active、:focus、:disabled 状态如果各自写死颜色,换主题时漏改一个就露馅。正确做法是在伪类中只覆盖变量值,让基础样式保持引用不变。
例如:
:root {
--btn-bg: #007bff;
--btn-bg-hover: #0056b3;
--btn-bg-active: #004085;
--btn-bg-disabled: #6c757d;
}
.btn {
background-color: var(--btn-bg);
}
.btn:hover {
--btn-bg: var(--btn-bg-hover);
}
.btn:active {
--btn-bg: var(--btn-bg-active);
}
.btn:disabled {
--btn-bg: var(--btn-bg-disabled);
}
- 这样改主题只需动
:root里的基础变量,所有状态自动同步 - 注意:变量覆盖只对当前选择器及其后代生效,不影响其他组件
- 不要在
@keyframes里用变量控制颜色动画——CSS 动画不响应变量变化,得靠 JS +element.style.setProperty
currentColor 才是真正的上下文感知载体
color: inherit 经常失灵:它只读父元素当前已计算出的 color 值,不响应变量变化,还容易被 UA 样式(如 a:link 默认蓝色)压住。真正能跨层级、实时联动的,是 currentColor。
currentColor 动态引用“自身 color 的计算结果”,不是继承父级。只要宿主元素设置了 color(哪怕通过 var(--text)),所有 currentColor 引用立刻刷新。
- SVG 图标写
fill: currentColor,图标颜色随文字自动同步 -
border-color: currentColor、text-shadow: 0 1px 1px currentColor全部跟着主题走 - 表单控件(
input、button)和链接(a)需手动打通:补全a:link, a:visited, a:hover, a:active { color: currentColor; } - Shadow DOM 中,
:host { color: var(--theme-text); }是前提,内部才能用::slotted(*) { color: currentColor; }
复杂点在于:currentColor 取的是“自己”的 color,不是“父级”的 color——所以宿主元素必须显式声明 color,否则它拿到的是 UA 默认值,不是你期望的主题色。


















