shadow dom 是唯一真正封装样式的机制,需显式调用 attachshadow() 创建,样式须用 createelement('style') 注入;css 变量通过继承透入,::slotted() 仅支持可继承属性,:host 用于响应宿主状态。

Shadow DOM 是唯一能真正封装样式的机制,不启用它,所谓“封装”只是心理安慰。 所有 class 命名、scoped 属性、BEM 约定都挡不住外部 button { color: red } 的覆盖;而 Shadow DOM 在浏览器样式计算阶段就跳过跨 boundary 匹配,!important 也无效。
如何正确创建 Shadow Root 并注入样式
必须显式调用 attachShadow(),且不能靠字符串拼接 innerHTML 注入 <style></style> —— 否则 <style></style> 被当普通 HTML 解析,不进 CSSOM,后续 JS 动态改样式会失效。
- 始终用
{ mode: 'open' }:方便 DevTools inspect,'closed'会让el.shadowRoot返回null,调试基本抓瞎 - 推荐分两步操作:先设结构(
shadowRoot.innerHTML = '<button><slot></slot></button>'),再用document.createElement('style')+textContent注入样式 - 避免在 shadow 内部写
body { color: red }——body不是宿主元素,也不在作用域内,浏览器压根不解析这条规则
为什么 CSS 变量能“穿透”,而普通选择器不能
CSS 变量(如 --primary)不是“穿透”,是继承。它顺着 DOM 树从宿主元素自然透入 shadow tree,仅限可继承属性链,且变量必须挂在宿主元素或其祖先上才有效。
- ✅ 正确:
<my-button style="--primary: #3b82f6;"></my-button>或<my-button class="theme-dark"></my-button>+.theme-dark { --primary: #1e1e1e; } - ❌ 无效:
<div class="wrapper"><my-button></my-button></div>+.wrapper { --primary: red; }—— 变量没挂到 host 上,进不去 shadow - 内部消费时务必带 fallback:
background-color: var(--primary, #007bff);,避免变量未定义导致样式崩溃
::slotted() 的能力边界与常见误用
::slotted() 是唯一能影响 slot 分发内容的伪类,但它只允许设置可继承属性(color、font、line-height、background-color),对布局类属性完全无效。
- 禁止写
::slotted(*) { margin: 16px; }——margin不可继承,浏览器直接忽略 - 允许写
::slotted(p) { color: var(--text-color); },但仅作用于传入 slot 的顶层<p></p>元素 - slot 分发的是 light DOM 节点的引用,不是复制节点;强行干预布局会破坏封装边界,浏览器明确禁止
:host 伪类响应外部状态的正确写法
:host 匹配宿主元素自身(即 <my-button></my-button> 这个标签),用于响应其 class、属性或上下文环境,但需注意语义差异。
-
:host([disabled])→ 响应<my-button disabled></my-button>,依赖attributeChangedCallback监听并同步属性(不能只改this.disabled = true) -
:host-context(.dark)→ 响应祖先有class="dark",如<my-button></my-button> -
:host(.primary)→ 只查宿主自身是否有class="primary",不是查祖先,别和:host-context混用
真正容易被忽略的是:Shadow DOM 不自动继承 font-family 和 color 以外的样式,比如 line-height、letter-spacing 都需要显式声明 :host { line-height: inherit; };还有,所有可定制视觉属性(圆角、阴影、间距)都应该通过 CSS 变量暴露,而不是硬编码或依赖继承链断裂的属性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











