Shadow DOM 是浏览器原生支持的 DOM 隔离机制,需显式调用 attachShadow() 创建,仅对标准或自定义元素有效;其 style 局部化、事件默认不穿透、JavaScript 仍共享全局作用域。

Shadow DOM 不是“新语法”或框架加的特性,它是浏览器原生支持的 DOM 隔离机制,从 Chrome 53、Firefox 63、Safari 10.1 开始稳定可用——如果你在现代浏览器里写自定义元素,它就默认在后台起作用。
attachShadow() 是唯一入口,不调用就根本没有 Shadow DOM
Shadow DOM 不会自动出现,必须显式调用 attachShadow() 才能为一个元素创建 shadow root。没有这一步,哪怕你写了 <my-button></my-button>,它也只是普通元素,样式和事件都暴露在外。
-
attachShadow()必须传入{ mode: 'open' }或{ mode: 'closed' };推荐始终用'open',否则 JS 无法通过element.shadowRoot访问内部结构,调试和测试基本瘫痪 - 同一个元素只能调用一次
attachShadow(),重复调用会直接抛错:Failed to execute 'attachShadow' on 'Element': Shadow root has already been attached - 不能对
<div>等普通元素随意 attach,但可以对任何标准 HTML 元素(包括<span>、<p>)或自定义元素(如<my-card>)调用
style 标签在 shadow root 内才真正“局部化”
放在 shadow root 里的 <style> 只影响该 shadow tree 内部节点,外部 CSS 选不到它,它也选不到外部元素——这不是靠命名约定或 BEM 实现的,是浏览器渲染层硬隔离。
- 不要把全局样式表 link 进 shadow DOM,
<link rel="stylesheet">在 shadow root 中无效(除非用adoptedStyleSheetsAPI) - 内部用
:host选择器控制宿主元素自身样式,用:host-context(...)响应外部环境(比如主题类),但后者兼容性差,慎用 - 如果用了 CSS-in-JS 库(如 styled-components),注意它默认不生成 shadow DOM 样式,需手动注入到
shadowRoot.innerHTML或用adoptedStyleSheets
事件不会自动穿透,但可主动配置冒泡行为
Shadow DOM 天然形成事件边界:内部 click 默认不会冒泡到 light DOM,外部监听不到;但你可以通过 composed: true 显式开启跨边界传播。
立即学习“前端免费学习笔记(深入)”;
- 自定义事件必须设
composed: true才能穿出 shadow boundary,否则document.addEventListener('my-event', ...)完全收不到 -
event.target在跨边界后会被重写为shadowHost(即宿主元素),这是为了保护内部结构不被外部探测——若需原始目标,要用event.composedPath()[0] - focus/blur 类事件默认不冒泡出 shadow DOM,需手动 dispatch 含
composed: true的新事件来通知外部
最常被忽略的一点:Shadow DOM 隔离的是 DOM 结构和样式作用域,不是 JavaScript 作用域。内部脚本仍共享全局 window,localStorage、fetch、定时器等完全不受影响——封装感来自渲染层,不是执行层。



















