css变量必须声明在宿主元素上才能被shadow dom读取,因继承链止于宿主而非:root或body;正确方式为行内style、宿主选择器css规则或js setproperty,并须带fallback以防样式崩塌。

变量必须声明在宿主元素上,否则 shadow 内部读不到
很多人写 body { --color: red; } 或 :root { --color: red; },结果 shadow 里 var(--color) 始终 fallback 到默认值——这不是 bug,是 Shadow DOM 的继承链被截断了。浏览器只沿 DOM 树向上查,<my-button></my-button> 的 shadow root 是继承终点,body 不在其父链上。
正确做法只有两种:
<my-button style="--color: #28a745;"></my-button>-
my-button { --color: #28a745; }(且该规则必须命中组件标签本身)
小程序中更严格:<van-button class="theme-dark"></van-button> + .theme-dark { --btn-bg: #333; } 才生效;写在父 <view></view> 上无效。
所有 var() 都要带 fallback,否则样式可能静默崩塌
var(--bg-color) 没 fallback 时,变量未定义就计算为 invalid value,整个属性会被丢弃。比如 background: var(--bg-color); 直接失效,变成透明背景。
务必写成 background: var(--bg-color, #007bff);,哪怕只是临时占位色。常见可定制项都应覆盖:
color: var(--text-color, #333);border-radius: var(--radius, 4px);box-shadow: var(--shadow, 0 1px 3px rgba(0,0,0,0.1));
拼错变量名(如 --btn-bk-color vs --btn-bg-color)或漏掉 fallback,是主题失效最隐蔽的原因。
::part() 和 exportparts 是补位方案,不是替代变量
当你要控制按钮里的图标颜色、输入框 placeholder、或禁用态文字透明度,而组件没暴露对应变量时,::part() 才有用武之地。
它需要组件内部配合:<svg exportparts="icon"></svg>,外部才能写 my-button::part(icon) { color: var(--icon-color); }。
注意限制:
- 不支持嵌套:
my-button::part(icon)::before无效 - 不能用
!important覆盖 shadow 内已设的内联style - Safari 17.4+、Chrome 95+、Firefox 119+、微信小程序基础库 2.28.0+ 才支持
调试时别只看 computed,要查“inherited CSS properties”
开发者工具 Elements 面板中,右键 shadow 内节点 → “Show inherited CSS properties”,能直接看到该节点实际继承到哪些变量值。比手动查 getComputedStyle(el).getPropertyValue('--color') 更直观。
真正容易被忽略的点是:变量名没统一约定、fallback 缺失、挂载位置错误——三者任一出问题,主题就会在某个组件里静默失效,没有任何报错提示。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











