应选择支持 Shadow DOM 的宿主元素(如 <div>、<span> 或自定义元素),确保元素已插入 DOM 或在自定义元素 constructor 中调用 attachShadow(),避免重复调用,并使用 mode: "open" 便于调试。

attachShadow() 报 “This element does not support shadow roots” 怎么办
这个错误不是代码写错了,而是宿主元素选错了。浏览器只允许在特定元素上挂载 Shadow DOM:
-
<div>、<span>、自定义元素(如<modal-dialog>)可以 -
<img>、<input>、<p>、<ul>等原生替换元素或语义化容器不支持 - 元素必须已插入 DOM,或至少完成构造(比如在自定义元素
constructor里调用是安全的) - 对同一元素重复调用
attachShadow()会触发InvalidStateError
shadowRoot.innerHTML = htmlString 为什么危险
直接赋值 HTML 字符串看似简单,但会引发三重风险:XSS、全局样式污染、脚本逃逸执行。
- 内联
<style>会进入全局 CSSOM,覆盖宿主页面样式 - 内联
<script>在全局上下文执行,this、window、document全指向主文档 - 未过滤的用户输入可触发 XSS,且 Shadow DOM 不提供自动转义
- 即使用了
DOMParser,也必须手动剥离<script>标签,否则仍可能执行
怎么安全注入 HTML + 样式到 Shadow DOM
核心原则:结构、样式、脚本三者分离处理,避免拼接字符串。
- 用
new DOMParser().parseFromString(html, 'text/html')解析 HTML 字符串 - 提取所有
<style>节点,逐个创建CSSStyleSheet实例,再通过shadow.adoptedStyleSheets = [...]注入(Chrome 73+ / Safari 16.4+ 支持) - 剥离所有
<script>标签;若需执行逻辑,必须显式绑定this、window、document到当前shadowRoot上下文 -
<link rel="stylesheet">必须代理请求,返回带scope属性的 CSS 文本,再构造CSSStyleSheet - 最终只把净化后的
doc.body子节点 append 到shadowRoot
:host 和 ::slotted 是唯一合法的跨边界样式钩子
外部样式无法穿透 Shadow DOM,想影响内部表现只能靠这两个伪类,且规则严格:
立即学习“前端免费学习笔记(深入)”;
-
:host匹配宿主元素自身,可用于响应属性变化(如:host([disabled]))或继承基础样式(:host { font-family: inherit; color: inherit; }) -
::slotted(*)仅作用于传入<slot>的节点,且只支持继承性属性(color、font、background-color),不能设margin、display等布局属性 - 别写
::slotted(*) { margin: 0; }—— 布局责任该由使用者承担,强行重置反而破坏封装 -
/deep/、::ng-deep、>>>等穿透语法已被弃用,现代浏览器不支持
<input> 或 <img>,连挂载都失败;而 mode: "closed" 表面安全,实际让 shadowRoot 对开发者不可见,调试时连结构都看不到——日常开发请坚持用 mode: "open"。



















