根本原因是变量声明作用域与使用位置不匹配:CSS自定义属性依赖继承链,仅后代元素可读取,:root是唯一确保全页面继承的位置;组件内声明(如.card { --pad: 1rem; })仅对该组件DOM树生效,全局规则无法访问。

CSS自定义属性(--x)在组件作用域里不生效,根本原因不是“变量没传进去”,而是**变量声明的作用域与使用位置不匹配**——你在组件内部声明了--x,但外部样式或父级上下文根本访问不到它。
为什么:root之外的变量在全局样式中无效?
CSS变量遵循继承机制,不是“全局注册”:只有被声明节点的后代元素才能读取该变量。组件级声明(如.card { --pad: 1rem; })只对.card及其子元素有效;而你写的全局覆盖规则(比如.btn { padding: var(--pad); })运行在根上下文,--pad根本未定义,结果var(--pad)计算为invalid,整条声明被浏览器丢弃。
-
:root是唯一能确保所有元素都可继承的位置(包括动态插入的第三方组件) -
html也可用,但权重略低,且某些框架(如NiceGUI)会重置html样式,导致变量丢失 - Vue/React组件内
<style scoped>或style.module.css中声明的--x,仅限该组件DOM树内生效,无法被其他组件或全局CSS引用
为什么::v-deep或/deep/不能穿透变量作用域?
深度选择器解决的是**样式规则作用域穿透**问题,不是变量作用域穿透。::v-deep .child { color: red }能让父组件样式影响子组件DOM,但它不会把父组件声明的--x注入到子组件的继承链里——子组件仍只能读取自己或祖先节点(如:root)定义的变量。
- 即使你用
::v-deep选中了子组件内的元素,var(--x)依然会按子组件自身的继承链查找--x - 想让子组件用上某个变量,必须让它能从
:root或其某级父容器继承到该变量,而不是靠选择器“强行注入” - 在Shadow DOM环境(如NiceGUI、Web Components)中,外部
:root变量默认不可穿透,需显式在影子根节点上设置
为什么构建后var(--x)在IE或旧版浏览器里直接消失?
IE11及更早版本不认识var(--x)语法,遇到就跳过整条声明,等价于写了个空值:padding: ;。PostCSS插件(如postcss-custom-properties)若未配置preserve: false,会保留原始var(--x)行,导致IE继续跳过——它永远看不到编译后的值。
立即学习“前端免费学习笔记(深入)”;
- 必须确认构建配置中
postcss-custom-properties的preserve设为false,否则编译输出里仍有var(--x) - 变量值必须是纯常量(
--c: red;),不能含calc()、嵌套var()或函数(如linear-gradient),否则插件无法静态求值 - 动态JS设置(
el.style.setProperty('--x', 'red'))在IE中需配合css-vars-ponyfill且watch: false才可靠
最常被忽略的一点:你以为在组件里写了--x就能到处用,其实它连同级兄弟组件都访问不到——变量作用域和CSS选择器作用域是两套独立系统,混淆这两者,90%的“变量不生效”问题就埋下了。


















