CSS变量的局部性依赖声明容器而非嵌套结构,须在父级元素(如.card)显式定义以供子元素继承;错误包括重复声明、误用嵌套语法、伪元素未兜底、滥用:root全局覆盖等,BEM中应于Block级类名声明变量,IE11不支持var()回退机制。

局部变量不是自动继承的,得在容器上显式声明
CSS变量的“局部”效果完全依赖声明位置,不是靠嵌套结构或文件划分。浏览器只看DOM树中谁最近设置了--color-bg,然后向下继承。如果你只在.card__header里写--color-bg: #1a1a1a,.card__footer根本读不到——它只会往上找.card或:root。所以真正有效的做法是:.card { --color-bg: #1a1a1a; },所有子元素用var(--color-bg)就自然拿到这个值。
常见错误包括:
- 在多个子选择器里重复声明同一变量,导致顺序敏感、覆盖混乱
- 误以为
.card { .header { --x: 1; } }这种写法能生效(原生CSS不支持嵌套语法) - 给伪元素
::before或@keyframes里直接var(--x)却不兜底——它们不继承父级变量
别碰:root做局部覆盖,它永远只匹配
:root { --color-bg: #121212; }就是全局改,哪怕你把它包在@media (prefers-color-scheme: dark)里也一样。想让深色模式只作用于某个卡片区域?必须放弃:root,改用具体容器类:.card--dark { --color-bg: #121212; --color-text: #e0e0e0; }。这样变量只在这个.card--dark及其后代里有效,其他区域完全不受影响。
顺带一提:button { --color-bg: red; }是合法且有效的,变量会从这个button节点开始向下继承;但button { :root { --color-bg: red; } }完全无效,浏览器直接忽略。
立即学习“前端免费学习笔记(深入)”;
和BEM类名配合时,变量声明要对齐Block边界
BEM的search-form是Block,它应该既是样式作用域的视觉边界,也是变量作用域的声明锚点。正确做法是:.search-form { --input-padding: 8px; --input-border-radius: 4px; },然后.search-form__input { padding: var(--input-padding); border-radius: var(--input-border-radius); }。这样变量和类名语义一致,调试时也能一眼看出归属。
容易踩的坑:
- 把变量声明在
.search-form__input里,结果.search-form__submit-button拿不到统一值 - 用
.search-form .button这种上下文选择器——它绕过了BEM隔离,等于主动凿穿围栏 - 在全局CSS文件里定义
.search-form { --x: ... },但多个组件共用同一份common.css,照样互相覆盖
IE11及以下不支持var(),别指望降级回退
IE里color: var(--text, #333)不会取#333作为fallback,而是直接回退到inherit或初始值,且控制台零提示。真要兼容,就得换思路:
- 放弃变量方案,用BEM类名切换:
.theme-dark .search-form__input和.theme-light .search-form__input分别写死样式 - 服务端根据
User-Agent判断是否注入变量方案,避免前端运行时判断 - 用
<style></style>标签配合高特异性选择器临时覆盖,但得确保它在全局样式之后加载
变量方案的“局部性”很脆弱:它依赖开发者始终在正确容器上声明、不滥用内联样式、避开不支持环境。一旦漏掉某一层,整条继承链就断了。


















