直接写 不等于 shadow dom 对话框,因其不自动创建 shadow dom,样式和结构暴露于全局;真正隔离需在自定义元素构造函数中调用 attachshadow({ mode: 'open' }) 并注入样式与结构。

为什么直接写 <dialog></dialog> 不等于 Shadow DOM 对话框
原生 <dialog></dialog> 元素本身不自动创建 Shadow DOM,它的样式和结构仍暴露在全局作用域中。你给 dialog::backdrop 加的样式可能被页面其他 CSS 覆盖;外部 JS 也能直接 document.querySelector('dialog').open() 干预行为,破坏封装。真正“独立”的对话框必须手动挂载 shadow root,否则只是语义化标签,不是隔离组件。
attachShadow({ mode: 'open' }) 必须在自定义元素构造函数里调用
不能在普通 <div> 上硬套,浏览器会抛 <code>DOMException: Failed to execute 'attachShadow' on 'Element': This element does not support shadow roots。只支持:自定义元素(如 <modal-dialog></modal-dialog>)、<div>、<code><span></span>、<section></section> 等容器型元素。
- 在
constructor()里调用this.attachShadow({ mode: 'open' })—— 此时元素已初始化,安全 - 重复调用会触发
InvalidStateError,检查是否已有 shadow root:if (!this.shadowRoot) { ... } - 绝对不用
mode: 'closed':调试时element.shadowRoot返回null,连 DevTools 都 inspect 不到内部按钮,改个 hover 色都要猜
样式必须进 shadowRoot,且需显式继承基础属性
Shadow DOM 默认不继承 font-family、line-height 等,但 margin、display 这类非继承属性不会透入。如果你没写 :host 规则,对话框文字可能突然变成 Times New Roman。
- 用
document.createElement('style')注入,而不是拼在innerHTML字符串里:shadowRoot.innerHTML = `<style>...</style>`会让<style></style>被当普通 HTML 解析,不进 CSSOM,后续 JS 改样式无效 - 开头必须加:
:host { font-family: inherit; color: inherit; line-height: inherit; } - 背景遮罩层要用
::backdrop伪元素,但它只对原生<dialog></dialog>生效;自定义组件得自己画一个<div class="backdrop"> 并控制 z-index <li>避免 <code>!important:它压制不了宿主页面的合理覆盖需求,比如主题色切换;改用:host-context(.dark) .close-btn { background: #333; } -
::slotted(h2) { margin: 0; font-size: 1.2em; }可以,但::slotted(*) { margin: 0; }不可靠,且违背封装原则 -
::slotted()只影响可继承属性(color、font、background-color),不能设padding或display—— 布局责任该由使用者承担 - 想让 slot 内容响应主题?用
:host-context(.theme-dark) ::slotted(*) { color: #fff; },别写成:host(.theme-dark) ::slotted(*),后者只查<modal-dialog class="theme-dark"></modal-dialog>,不查
::slotted() 是唯一合法传入内容的样式出口
用户通过 <modal-dialog><h2 slot="title">确认删除</h2>
<p slot="content">确定要永久移除吗?</p></modal-dialog> 传内容,但这些内容默认不受 shadow 内部样式控制——除非你用 ::slotted() 显式接管。
button { background: red !important; },shadow 里的按钮也完全不受影响——但前提是,你真调用了 attachShadow(),并且没把样式漏到外面。











