::part() 仅匹配 Shadow DOM 内显式标注 part 属性的元素,大小写敏感、不可链式选择、不能自用,且完全依赖组件作者主动暴露;未加对应 part 属性则样式静默失效。
因为 ::part() 不是穿透选择器,它只匹配 Shadow DOM 内部显式带 part="xxx" 属性的元素。外部写 my-input::part(label),但组件内部的 <span> 没加 part="label",样式就完全不应用——浏览器静默忽略,连控制台警告都没有。
part="Label" 和 ::part(label) 不匹配part="icon-slot" ≠ ::part(icon)
my-button::part(wrapper) input 或 my-button::part(label)::before 是非法语法::host::part(label) 无效,::part() 只能在 light DOM 或父级 shadow 中使用你作为调用方,没有任何办法绕过这一步。是否能用 ::part(),完全取决于组件是否在内部 HTML 节点上加了 part 属性。比如想定制加载图标颜色,组件里得这么写:
<div part="loader" class="spinner"></div>
否则你写 my-button::part(loader) 就是空转。没有第四个办法:!important、全局 class、把 <style> 放 <head> 全部无效。
part="div1";推荐语义化命名:part="icon"、part="error-message"
part 列表,直接查它的 shadow DOM 结构(DevTools → Elements → 展开 shadow root)看有没有 part 属性::slotted() 用于样式化被 <slot> 投射进来的外部内容,而 ::part() 用于样式化组件自己 shadow 内、带 part 属性的原生节点。两者作用域和目标完全不同。
<my-button><span slot="icon">★</span></my-button> 里 ★ 的颜色 → 用 ::slotted([slot="icon"])
<div class="spinner"> → 组件得先加 part="spinner",然后你写 my-button::part(spinner)
::slotted() 能穿透一层 slot,但无法选中 slot 内部再嵌套的子元素(除非那层也用了 <slot>)::part() 需 Chrome 97+ / Edge 97+ / Safari 16.4+;::slotted() 支持更早(Chrome 53+)单靠 ::part() 只能设静态样式,真正灵活的定制要结合 :host() 的参数函数,比如根据属性切换样式:
:host([disabled]) ::part(button) { opacity: 0.5; cursor: not-allowed; }
但注意:只有在 static get observedAttributes() 里声明的属性变更,才会触发 :host() 重匹配。
disabled、size、variant,并在 observedAttributes 中列出:host(.class) —— 宿主元素 class 变化不会触发 shadow 内样式更新part,或者你误把 ::slotted() 的场景当成了 ::part() 的场景。