custom elements 必须在 constructor() 中调用 attachshadow({ mode: 'closed' }) 才能实现样式隔离,延迟调用或使用 open 模式均无法阻止全局样式穿透;js 隔离需沙箱拦截 document/window 访问,adoptedstylesheets 有局限,iframe 是唯一原生 js 隔离方案但开销大。

Custom Elements 不调用 attachShadow() 就没有样式隔离
直接注册自定义标签如 customElements.define('my-app', MyApp),只是让浏览器认识这个标签名,DOM 仍插入在 light DOM 中。所有外部 CSS(比如 button { color: red })和子应用自己的全局样式(如 .header)都会穿透进来。
常见错误现象包括:
- 子应用的
normalize.css把主应用body字体大小重置了 - 父应用的
[data-theme="dark"] .btn意外命中子应用未加前缀的按钮 - 两个子应用都定义
.modal-overlay,后加载的覆盖 z-index,遮罩失效
根本原因:Custom Element 本身不创建 Shadow DOM,也不做任何作用域划分。“组件化”仅停留在命名层面。
attachShadow({ mode: 'closed' }) 必须在 constructor() 中调用
这是生产环境唯一有效的样式边界建立方式。延迟到 connectedCallback 或更晚调用,等于在 DOM 已挂载、样式已计算后才补隔离墙——污染早已发生。
关键细节:
-
mode: 'open'允许任意脚本通过el.shadowRoot修改内部样式或节点,等于主动放弃隔离能力 - CI/CD 流水线应强制检查:所有
attachShadow调用必须含{ mode: 'closed' },否则阻断构建 -
mode: 'closed'下el.shadowRoot返回null,但 DevTools 可显示#shadow-root节点(需开启“Show user agent shadow DOM”)
注意:closed 模式下无法用 JS 直接读写 shadow 内容,这是安全代价——微前端中,子应用的样式注入、资源加载、生命周期管理应由宿主桥接,而非开放底层访问。
不能用 shadowRoot.innerHTML = htmlString 注入子应用 HTML
直接赋值会绕过 Shadow DOM 的封装机制:<style></style> 标签内容逃逸到全局作用域,<script></script> 在全局上下文中执行,既污染样式又带来 XSS 风险。
正确做法是用 DOMParser 解析后分治处理:
- 提取所有
<style></style>内容,转为CSSStyleSheet实例,再通过shadowRoot.adoptedStyleSheets = [sheet]注入(Chrome 73+ / Safari 16.4+ 支持) - 拦截
<script src=""></script>,fetch 后在沙箱中执行(重绑定this/window/document到当前 shadow 上下文) - 剥离内联
<script></script>,避免意外执行
adoptedStyleSheets 不是万能解:它不支持 @import、相对路径(如 url(./img.png))、CSS 变量继承链断裂等问题,这些需前置编译或代理处理。
HTML 节点映射必须区分 light DOM 与 shadow DOM 边界
子应用的 document.querySelector、document.body.classList.add('dark') 等操作依然会穿透影响主应用。Shadow DOM 只隔离样式作用域,不隔离 JS 执行环境。
这意味着:
- 所有对
document、window、history的访问必须被沙箱拦截并重定向到当前 shadow 上下文(例如把document.body映射为shadowRoot.host.parentElement) - 事件监听(如
popstate)需桥接,避免多个子应用重复注册 -
micro-app[name="xxx"]这类属性选择器方案本质是 light DOM 隔离,依赖主应用统一包裹和前缀注入,不适用于原生 Custom Elements 场景
真正需要 JS 执行隔离时,iframe 是唯一浏览器原生方案,但它带来独立渲染进程、内存开销翻倍、移动端滚动穿透等硬伤——除非子应用完全不可信(如银行支付页),否则优先选 Shadow DOM + JS 沙箱组合。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











