css变量不穿透shadow dom,而是通过继承链从宿主元素向上查找;必须将变量定义在宿主元素上(如行内style、css规则绑定:host或js设置),否则无效;消费时需显式使用var()并提供fallback。

CSS变量能“穿透”Shadow DOM,不是靠穿透,而是靠继承链天然跨过边界——但变量必须挂在宿主元素上,否则压根找不到。
为什么body或.theme-dark里设--color完全无效
浏览器计算var(--color)时,只从当前元素出发,沿 DOM 树向上找定义,直到宿主元素(比如<my-button></my-button>)就停了。它不会继续往上查body或:root——那些节点根本不在继承链上。
-
body { --color: red; }→ Shadow 内部var(--color)显示invalid,DevTools 的“Computed”面板里都看不到这条变量 -
<div class="wrapper"><my-button></my-button></div>+.wrapper { --color: red; }→ 同样无效,变量没挂到my-button自身 - React/Vue 把主题 CSS 注入
document.head?照样穿不进,Shadow DOM 不读全局样式表
正确挂载变量的三种方式(必须作用于宿主自身)
变量得“贴”在<my-button></my-button>这个标签上,才能被内部继承到。选一种用就行:
- 行内
style:<my-button style="--bg: #1e1e1e; --text: #fff;"></my-button> - CSS 规则绑定宿主:
my-button[theme="dark"] { --bg: #1e1e1e; --shadow: 0 2px 8px rgba(0,0,0,0.2); } - JS 动态设置:
el.style.setProperty('--bg', '#2d2d2d')(适合主题切换)
注意::host { --bg: var(--bg); }这句不是多余——它确保变量名一致且可被子元素继承;但别写:host { --bg: var(--bg, #fff); },fallback 可能触发无限递归。
var(--x)必须带 fallback,否则会回退到初始值
没 fallback 的var(--x)一旦未定义,就按属性默认值走:background-color: var(--bg) → background-color: transparent,不是白色;color: var(--text) → color: inherit,可能变成黑色。
- ✅ 正确:
color: var(--text, #333); background: var(--bg, #fff); - ❌ 危险:
border-color: var(--border);→ 未定义时变border-color: initial,即transparent,边框直接消失 - iOS Safari 16.4 之前有引擎级 bug:哪怕宿主挂了变量,Shadow 内仍读不到,需 UA 检测降级
别指望::slotted()或:host帮你转发变量
::slotted()只能影响插槽内容的顶层可继承属性(如color、font-family),不能传变量;:host只控制宿主自己,不自动传导到子元素。
-
:host { --bg: #f0f0f0; }→ 宿主元素自身有了变量,但内部<p></p>还是用 UA 默认色 - 必须配对写:
p { color: inherit; }或:host > p { color: var(--text, #333); } -
::slotted(p) { color: var(--text); }→ 有效,但只对 slot 分发进来的顶层<p></p>起作用,嵌套在里面的<span></span>不受影响
真正容易被忽略的是:所有变量消费点都得显式写var(),继承不会自动把--text变成color值——你得亲手写出来,一个都不能少。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











