::part() 是组件作者主动在 shadow DOM 内标记 part 属性后,外部才能样式化的方式;必须静态声明、大小写严格匹配、仅作用于 shadow 内真实节点,不支持 slot 或宿主元素,且需兼容性降级。

::part() 不是穿透工具,是组件作者主动开的“样式小窗”——没在 shadow 内写 part="xxx",外部写再多 my-component::part(xxx) 都不生效。
为什么 ::part() 写对了却完全没反应
常见错误不是语法错,而是前提缺失。浏览器根本不会报错,只会静默忽略:
-
::part(label)失效?先查组件 shadow tree 里有没有真实节点带part="label"属性(注意:不是class="label",也不是data-part="label") - 大小写必须严格一致:
part="Label"和::part(label)不匹配 -
<slot></slot>投影进来的内容不能用::part()选中——那是::slotted()的事 - 宿主元素(比如
<my-input></my-input>标签本身)不能加part属性,::part()只作用于 shadow 内部子节点
怎么让 ::part() 真正生效(组件作者视角)
如果你在开发自定义组件,暴露可定制部位必须显式、静态、贴近语义:
- 在 shadow 内部 HTML 中直接写:
<div part="loader"></div>或<span part="label required"></span>(多个值空格分隔) - 不要动态绑定:
part={this.state.type}无效,part必须是静态字符串属性 - 别试图在
<slot>上加part—— slot 本身不是渲染节点,它只是内容占位符 - 想支持图标颜色定制?得给内部图标容器加
part="icon",而不是指望外部靠::slotted([slot="icon"])控制
::part() 的兼容性现实和降级方案
Chrome/Edge 97+ 原生支持,但 Safari 和 Firefox 仍不可靠:
立即学习“前端免费学习笔记(深入)”;
- Safari 自 15.4 起支持,但需用户手动开启
about:config中的 Experimental Web Platform Features;iOS 15.3 及更早设备完全不认 - Firefox 截至 2026 年 5 月仍未实现,
@supports selector(::part(foo))永远返回false - 真机测试底线:macOS 12.6 + Safari、iOS 16.7 + Safari,别信 CanIUse 的“支持”标记就上线
- 降级必须做:
@supports包裹关键样式,fallback 到 CSS 自定义属性,例如:@supports selector(::part(label)) { my-component::part(label) { color: var(--label-color, #333); } } @supports not selector(::part(label)) { my-component { --label-color: #333; } }组件内部再用var(--label-color)消费
别混淆 ::part()、:host 和 ::slotted()
三者解决不同层级问题,混用等于白写:
-
:host只控制宿主元素自身(如<my-button disabled></my-button>),改不了内部任何子节点 -
::slotted()只影响被<slot>投影进来的外部内容(比如你传进去的<svg>),不能设display或margin等布局属性 -
::part()是唯一能对 shadow 内部原生节点做完整样式控制的方式(包括border-radius、cursor、background) - 例如:想改按钮内部 loader 的旋转颜色,
:host .spinner无效(穿不透),::slotted(.spinner)无效(它不是插槽内容),只能靠组件内<div part="loader">+ 外部my-button::part(loader)
真正容易被忽略的是:part 名称一旦公开,就是组件 API 的一部分。改名 = 破坏性变更,必须同步文档、版本号和迁移指南;而很多人只在本地 demo 里试通。


















