直接 innerhtml 拼接 style 会失效,因 style 标签被当普通 html 解析而不注册进 cssom;正确做法是先设结构再用 dom 方法注入 style 节点,或使用 adoptedstylesheets。

为什么直接 innerHTML 拼接
Shadow DOM 的样式必须进入 CSSOM 才能参与计算和动态更新,而 shadowRoot.innerHTML = `<style>...</style>` 会让 <style></style> 标签被当作普通 HTML 解析,不注册进样式系统。后续 JS 修改 style.textContent 或切换主题时完全无响应,甚至触发 FOUC。
- 永远分两步:先设结构(
shadowRoot.innerHTML或shadowRoot.appendChild()),再用 DOM 方法注入样式节点 - 推荐写法:
const style = document.createElement('style'); style.textContent = '...'; shadowRoot.appendChild(style); - 若需复用基础样式(如字体重置、变量定义),用
new CSSStyleSheet()+shadowRoot.adoptedStyleSheets,但注意 Safari 16.4+、Chrome 73+ 才稳定支持 - 禁止在字符串模板里插值生成
style.textContent,易引入 XSS 风险
如何让外部主题或 class 真正影响 Shadow 内容
浏览器只认 :host 和 ::slotted() 这两个伪类作为跨 boundary 的合法通道,其它写法(如 /deep/、::ng-deep)已在 Chrome 120+ 和 Firefox 115+ 中移除,继续使用等于放弃兼容性。
-
:host只匹配宿主元素自身,例如:host([size="large"]) { padding: 12px 24px; }响应属性变化 -
:host(.dark)是当前推荐方式,:host-context(.dark)已被标记为 deprecated -
::slotted(p)只作用于传入<slot></slot>的顶层<p></p>节点,且仅支持可继承属性(color、font-family、line-height、background-color) - 禁止写
::slotted(*)或:host ::slotted(*)—— 行为不一致,且违背封装意图
part 属性不是自动穿透开关,而是需组件主动透传的锚点
part="header" 本身不提供任何样式能力,它只是个命名标签;外部写 my-card::part(header) { color: blue; } 永远无效,除非组件在 shadowRoot 内显式声明 :host ::part(header) 规则。
- 必须由组件作者在 shadowRoot 的
<style></style>中写:host ::part(header) { ... },否则外部选择器匹配不到任何节点 -
part值大小写敏感:part="Header"和part="header"是两个不同锚点 -
::part()是原子选择器,不支持链式写法:::part(header) .title中的.title会被浏览器丢弃 - 想暴露多个 part?必须在组件内逐一声明规则,例如
:host ::part(header), :host ::part(footer) { border-top: 1px solid #e5e7eb; }
复杂片段封装时最容易忽略的继承断点
Shadow DOM 不自动继承父级的 font-family、color、line-height 等,但也不会继承用户代理默认值(如 <input> 的默认颜色),导致文字渲染异常——这不是 bug,是边界行为。
- 必须在 shadowRoot 的顶层样式中显式写
:host { font-family: inherit; color: inherit; line-height: inherit; } - 布局类属性(
margin、display、width)不会继承,也不该由组件强制控制;slot 内容的布局责任始终属于使用者 - CSS 自定义属性(
--text-primary)靠继承穿透,不是“通信机制”,所以宿主页面必须提前设置,组件内部要提供 fallback:color: var(--text-primary, #333); - 重复调用
attachShadow()会抛出DOMException: Failed to execute 'attachShadow' on 'Element': Shadow root cannot be created on a node already hosting a shadow root.,检查是否在已挂载 shadow 的元素上再次初始化
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











