Shadow DOM 通过宿主节点与 shadow root 的树级隔离实现样式封装,:host 伪类是控制宿主样式的唯一方式,:host-context() 支持基于外部 light DOM 环境定制样式,需避免全局选择器和穿透语法以维持封装性。

Shadow DOM 通过宿主节点(host element)实现样式封装,核心在于利用 shadow root 的边界隔离机制,让组件内部样式默认不泄露、外部样式默认不穿透。关键不是“用宿主节点写样式”,而是**以宿主为锚点,结合特定选择器和作用域规则控制样式作用范围**。
宿主节点是 Shadow DOM 的根容器
创建 Shadow DOM 时,调用 element.attachShadow({ mode: 'open' }) 返回的 shadow root,其父节点就是宿主节点(即 element)。所有内部 DOM 都挂载在 shadow root 下,与宿主节点形成树级隔离:
- 宿主节点属于 light DOM,可被外部 CSS 选中(如
my-button { color: red; }) - shadow root 内部的元素默认不受外部样式影响(除非显式启用
:host或all: initial等例外) - 宿主节点本身不能直接在 shadow 内用普通选择器(如
div)匹配——它不在 shadow tree 中
:host 伪类控制宿主在 Shadow 内的表现
在 shadow DOM 内部的样式表中,:host 专门匹配宿主节点自身,是实现“组件级样式入口”的唯一方式:
-
:host { display: inline-block; }—— 设置宿主默认显示行为 -
:host(.primary) { background: blue; }—— 响应宿主上设置的 class -
:host(:hover) { opacity: 0.9; }—— 基于宿主状态定义交互样式 -
:host > * { margin: 0; }—— 仅作用于宿主的直接子元素(注意:这些子元素是 light DOM 插槽内容,非 shadow 内部节点)
:host-context() 支持基于外部环境条件定制样式
当需要根据宿主在外部文档中的上下文(如祖先类名、主题属性)调整内部表现时,可用 :host-context():
-
:host-context(.dark-theme) :host { background: #222; }—— 若宿主位于.dark-theme容器内,则整个组件应用深色背景 -
:host-context(html[lang="zh"]) .label { font-family: "PingFang SC"; }—— 按页面语言切换字体 - 注意:
:host-context()只能向上查找 light DOM 的祖先,无法跨 shadow boundary 匹配其他组件的 shadow 内部节点
避免样式穿透的常见实践
封装不是自动发生的,需主动规避泄漏风险:
- 不在 shadow 内使用全局选择器(如
button、h1),改用带前缀或 BEM 类名(如.my-button__icon) - 慎用
/deep/、::ng-deep(已废弃)或!important,它们破坏封装性 - 若需暴露部分样式钩子,用 CSS 自定义属性(
--my-button-bg)并在:host中赋值,由外部设置 - 插槽(
<slot>)内容属于 light DOM,其样式由外部控制;如需统一风格,可在 shadow 内对slot设置all: initial后重置,或用::slotted(*)有限干预


















