直接 innerhtml 拼接 会失效,因浏览器将其当作普通 html 节点而非样式处理,需用 document.createelement('style') 动态注入;:host 和 ::slotted() 是唯一合法跨边界样式钩子,且 shadow dom 不自动继承字体颜色等属性,须显式声明 inherit。

为什么直接 innerHTML 拼接 <style></style> 会失效
不是样式写错了,是浏览器根本没把它当样式处理。当你用 shadowRoot.innerHTML = `<div></div>
<style>.btn { color: red }</style>`,<style></style> 标签会被当成普通 HTML 节点解析,不进入 CSSOM,后续 JS 改 style.textContent 或访问 sheet.cssRules 全部无效。
- 必须分两步:先设结构(
shadowRoot.innerHTML = '<button><slot></slot></button>'),再用 DOM 方法注入样式节点 - 始终用
document.createElement('style')+textContent+appendChild(),避免字符串插值 XSS 风险 - 若需复用基础样式(如字体、重置行高),提前创建
CSSStyleSheet实例,再赋给shadowRoot.adoptedStyleSheets(注意 Safari 16.4+ / Chrome 73+ 才稳定支持)
:host 和 ::slotted() 是唯一合法的跨边界样式钩子
想让外部 class 或主题影响组件?只能靠这两个伪类。其它任何“穿透”写法(比如 /deep/、::ng-deep、> 子选择器匹配 slot 内容)要么已被移除,要么行为不一致。
-
:host只匹配宿主元素自身(即<my-button></my-button>这个标签),不能写:host div.title去选内部子元素 -
:host([disabled])有效,:host-context(.theme-dark)已被 Chrome/Firefox 标记为 deprecated,应改用:host(.theme-dark) -
::slotted(p)只作用于传入<slot></slot>的顶层<p></p>元素,且仅支持可继承属性(color、font-family、line-height、background-color);写::slotted(*) { margin: 8px }会被浏览器忽略
动态插入第三方 HTML 时,Shadow DOM 不等于沙箱
Shadow DOM 提供的是节点边界隔离,不是 JavaScript 或网络请求沙箱。直接 shadowRoot.innerHTML = fetchedHtmlString 会让其中的 <script></script> 全局执行、<link rel="stylesheet"> 发起跨域请求、onclick 属性触发任意逻辑。
- 必须用
DOMParser解析字符串,遍历移除所有<script></script>标签和onXXX属性(如onclick、onload) -
<style></style>内容可保留,但建议重写选择器加前缀或包裹进:host,避免意外匹配宿主 - 禁用自动加载
<link>,改为预取后内联注入文本,或完全拒绝 -
mode: 'closed'对脚本执行无约束力——它只屏蔽element.shadowRoot访问,不影响 HTML 解析阶段行为
字体、颜色等基础属性不会自动继承,必须显式声明
Shadow DOM 内部默认不继承宿主的 font-family 或 color,除非你主动写 :host { font-family: inherit; color: inherit; }。否则用户代理样式(比如 <input> 默认的 color: -internal-light-dark(black, white))会覆盖继承链。
- 在注入的
<style></style>中第一行就写:host { font-family: inherit; color: inherit; } - CSS 自定义属性(如
--primary)靠继承透入,但变量必须挂在宿主或其祖先上才有效;<div class="wrapper"><my-button></my-button></div>+.wrapper { --primary: red }是无效的 - 消费变量时务必带 fallback:
background-color: var(--primary, #007bff);,避免未定义导致样式崩溃
:host 语法或漏掉 inherit,就可能让组件在不同上下文中表现不一;而把未经净化的 HTML 直接塞进 shadowRoot,哪怕用了 mode: 'closed',照样执行脚本、泄露数据。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











