Shadow DOM 仅隔离 DOM 结构与样式,不隔离 JavaScript;样式需显式重置继承属性,查询受限于边界,事件默认跨边界冒泡,可控接口仅有 :host、::slotted 和 CSS 自定义属性。

Shadow DOM 不提供 JavaScript 作用域隔离,它只做 DOM 结构和 CSS 样式的封装。脚本执行环境始终共享全局 window,所谓“隔离”仅体现在 DOM 查询、样式作用范围和事件冒泡路径上。
样式隔离:边界明确,但需主动管理
外部样式默认无法穿透 shadow boundary 作用到 shadow tree 内部元素;同样,shadow root 中的
- 必须在 :host 或 shadow root 根节点上显式重置,例如:
:host { all: initial; font-family: system-ui; } - 想让外部控制组件外观,要用 CSS 自定义属性(
--my-btn-bg),并在内部用var(--my-btn-bg, #007bff)接入 -
::slotted(*)只能设置可继承样式(color、font、line-height),不能改 margin、display 或 position
DOM 查询与节点可见性:天然受限
document.querySelector('.item') 查不到 shadow tree 里的 .item;同理,shadowRoot.querySelector('.item') 也查不到 light DOM 中的节点。这是浏览器强制的查询边界。
- 判断一个元素是否在 Shadow 内:调用
el.getRootNode(),返回ShadowRoot即表示处于影子树中 - 宿主元素(host)始终是普通 DOM 节点,可被外部选中和操作;真正被“藏起来”的是 shadow tree 内的所有子节点
-
mode: "closed"会让el.shadowRoot返回 null,但不影响样式继承或事件冒泡,仅阻断 JS 对 shadowRoot 的直接访问
脚本执行:完全不隔离,JS 环境仍是同一个
Shadow DOM 内的 <script> 标签运行在主文档全局上下文中,能自由读写 window、localStorage、fetch 数据,也能通过 document.querySelector 拿到 body 并修改它——这不是 bug,是设计如此。</script>
立即学习“Java免费学习笔记(深入)”;
- 若需真正限制第三方脚本行为,必须配合 iframe(隔离 JS 执行上下文)+ CSP(限制资源加载)+ sandbox 属性
- 事件默认是
composed: true,所以 click 从 shadow 内按钮发出后,仍会冒泡到 light DOM 的监听器中 - 想阻止跨边界事件传播,可在 shadow root 边界调用
event.stopPropagation(),或创建自定义事件时设composed: false
真正可控的“接口”只有三类
Shadow DOM 的设计哲学不是封闭一切,而是暴露有限、明确的定制入口:
-
:host:控制宿主自身样式(尺寸、禁用态、主题响应) -
::slotted:约束 slot 插入内容的呈现风格(仅限继承属性) - CSS 自定义属性:作为组件对外提供的样式 API,由使用者传入值,组件内部消费


















