CSS ::part的用法
下图展示的是 Chrome 浏览器中 input="range" 输入框元素的 Shadow DOM 结构。
图 1 范围选择框的Shadow DOM结构
其中有一个非标准的 HTML 属性 pseudo,点击这个元素,可以看到有一段浏览器内置的 CSS 规则,如下图所示。
图 2 范围选择框的自定义伪元素示意
其中的伪元素 ::-webkit-slider-runable-track 正好就是 pseudo 属性的属性值,而开发人员可以利用这个伪元素对浏览器内置的组件样式进行重置,如下图所示。
图 3 范围选择框的样式重置示意
为什么要这样设计呢?原因很简单,那就是默认情况下,Shadow DOM 外部的 CSS 代码是无法改变 Shadow DOM 内部元素的样式的。浏览器只能通过暴露某些私有属性或者私有伪元素的方法,让开发人员有机会在外部重置 Shadow DOM 元素的样式。
下面问题来了。浏览器默认的组件可以通过私有的伪元素暴露,那么 Web Components 自定义元素组件有没有办法暴露 Shadow DOM 中的元素,以便让开发人员可以从外部对组件进行样式设置呢?
有的,且方法还不止一个。其中一个方法就是使用 CSS 变量,另一个方法则是使用 ::part 伪元素,这个伪元素就是专门用来穿透 Shadow DOM 进行样式设置的。语法如下:
一例胜千言,还是以 <square-img> 这个例子示意,比方说我们希望可以在外部重置该组件内部图像和描述的样式,则可以给图像和描述对应的元素设置 part 属性,下面是具体的代码:
图 4 part属性值设置示意
接下来,我们就可以使用 ::part 伪元素穿透 Shadow DOM 元素的上下文,对内部的元素进行样式设置了。例如:
图 5 :part伪元素穿透shadow DOM元素的效果示意
<slot> 元素可以看成一个占位符元素(国内多称之为“插槽元素”),可以把组件外部完成的 DOM 元素“替换”到 Shadow DOM 内部。
我们不妨继续使用 <square-img> 这个例子,这次我们在描述文字的前面插入一个 <slot> 元素,以便我们插入类似图标这样的前置元素。此时的 Shadow DOM 结构如下:
假设 .icon-info 元素显示的是图标,则下面的CSS代码就可以控制图标的颜色和文字的右间距:
图 6 ::part伪元素作用于<slot>元素示意
图 1 范围选择框的Shadow DOM结构
其中有一个非标准的 HTML 属性 pseudo,点击这个元素,可以看到有一段浏览器内置的 CSS 规则,如下图所示。
图 2 范围选择框的自定义伪元素示意
其中的伪元素 ::-webkit-slider-runable-track 正好就是 pseudo 属性的属性值,而开发人员可以利用这个伪元素对浏览器内置的组件样式进行重置,如下图所示。
图 3 范围选择框的样式重置示意
为什么要这样设计呢?原因很简单,那就是默认情况下,Shadow DOM 外部的 CSS 代码是无法改变 Shadow DOM 内部元素的样式的。浏览器只能通过暴露某些私有属性或者私有伪元素的方法,让开发人员有机会在外部重置 Shadow DOM 元素的样式。
下面问题来了。浏览器默认的组件可以通过私有的伪元素暴露,那么 Web Components 自定义元素组件有没有办法暴露 Shadow DOM 中的元素,以便让开发人员可以从外部对组件进行样式设置呢?
有的,且方法还不止一个。其中一个方法就是使用 CSS 变量,另一个方法则是使用 ::part 伪元素,这个伪元素就是专门用来穿透 Shadow DOM 进行样式设置的。语法如下:
::part(xxx) {}其中的参数 xxx 指的就是 Shadow DOM 元素的 part 属性值。
一例胜千言,还是以 <square-img> 这个例子示意,比方说我们希望可以在外部重置该组件内部图像和描述的样式,则可以给图像和描述对应的元素设置 part 属性,下面是具体的代码:
// 给图像元素设置part属性 var img = document.createElement('img'); img.setAttribute('part', 'img'); // 给描述元素设置part属性 var span = document.createElement('span'); span.setAttribute('part', 'span');此时的 Shadow DOM 结构如下图所示。
图 4 part属性值设置示意
接下来,我们就可以使用 ::part 伪元素穿透 Shadow DOM 元素的上下文,对内部的元素进行样式设置了。例如:
square-img::part(img) { border-radius: 40% 40% 0 0; } square-img::part(span) { background-color: #cd0000; }给图像设置上圆角,给标题设置红色背景,此时就会有下图所示的效果,可以看到无论是图像的圆角还是标题的背景色都表现为预期的样式。
图 5 :part伪元素穿透shadow DOM元素的效果示意
::part伪元素对<slot>元素也是有效的
::part 伪元素不仅对常规的 HTML 元素有效,对 Web Components 中独有的 <slot> 元素也是有效的。<slot> 元素可以看成一个占位符元素(国内多称之为“插槽元素”),可以把组件外部完成的 DOM 元素“替换”到 Shadow DOM 内部。
我们不妨继续使用 <square-img> 这个例子,这次我们在描述文字的前面插入一个 <slot> 元素,以便我们插入类似图标这样的前置元素。此时的 Shadow DOM 结构如下:
<img src="1.jpg" width="200" height="200"> <span> <slot name="prefix" part="prefix"></slot>注意图标尺寸和位置 </span>而在页面中组件对应的 HTML 结构为:
<square-img src="1.jpg" alt="注意图标尺寸和位置"> <i class="icon-info" slot="prefix"></i> </square-img>此时,.icon-info 这个元素就会作为 Shadow DOM 中 <slot> 元素的子元素显示。因此,若想设置 .icon-info 的样式,既可以直接针对选择器 .icon-info 进行设置,也可以借助 ::part 伪元素设置 <slot> 元素的样式,从而间接影响 .icon-info 元素的效果。这尤其适用于一些继承样式,例如颜色、字号、行高等。
假设 .icon-info 元素显示的是图标,则下面的CSS代码就可以控制图标的颜色和文字的右间距:
/* 直接对图标样式进行设置 */ .icon-info { display: inline-block; width: 1em; height: 1em; --mask: url(data:image/svg+xml;base64,...) no-repeat center / 100%; -webkit-mask: var(--mask); mask: var(--mask); background-color: currentColor; vertical-align: middle; } /* 通过<slot>元素微调图标样式 */ square-img::part(prefix) { display: inline-block; margin-right: .25rem; font-size: 14px; }最终实现的效果如下图所示。
图 6 ::part伪元素作用于<slot>元素示意