跳到主要内容
版本:v6

CSS 阴影部分

CSS 阴影部分允许开发者样式化影子树(shadow tree)内元素的 CSS 属性。这对于自定义 Ionic Framework 的 Shadow DOM 组件非常有用。

为什么需要 Shadow Parts?

Ionic Framework 是一组分布式 Web Components。Web Components 遵循 Shadow DOM 规范以封装样式和标记。

备注

Ionic Framework 组件并非全部是 Shadow DOM 组件。如果组件是 Shadow DOM 组件,其组件文档的右上角会有一个徽章。Shadow DOM 组件的一个示例是按钮组件

Shadow DOM 有助于防止样式从组件中泄漏并不经意地应用到其他元素上。例如,我们为 ion-button 组件分配了一个 .button 类。如果没有 Shadow DOM 封装,如果用户在自己的某个元素上设置了 .button 类,它将继承 Ionic Framework 的按钮样式。由于 ion-button 是一个 Shadow 组件,这就不是问题了。

但是,由于这种封装,样式也无法渗透到 Shadow 组件的内部元素中。这意味着如果 Shadow 组件在其影子树内渲染元素,则无法直接使用 CSS 定位内部元素。以 ion-select 组件为例,它渲染了以下标记:

<ion-select>
#shadow-root
<div class="select-text select-placeholder"></div>
<div class="select-icon"></div>
</ion-select>

占位符文本和图标元素位于 #shadow-root 内部,这意味着以下 CSS 将不能用于样式化占位符:

/* 不起作用 */
ion-select .select-placeholder {
color: blue;
}

那么如何解决这个问题呢?CSS 阴影部分

阴影部分说明

阴影部分允许开发者从影子树外部样式化影子树内部。为此,part 必须被暴露,然后可以通过使用 ::part 进行样式化。

暴露 part

创建 Shadow DOM 组件时,可以通过在元素上分配 part 属性来向影子树内的元素添加 part。这是在 Ionic Framework 中添加到组件的,不需要最终用户执行任何操作。

继续以 ion-select 组件为例,标记更新如下:

<ion-select>
#shadow-root
<div part="placeholder" class="select-text select-placeholder"></div>
<div part="icon" class="select-icon"></div>
</ion-select>

上面显示了两个部分:placeholdericon。有关其所有部分,请参阅 select 文档

有了这些暴露的部分,现在可以使用 ::part 直接样式化元素。

::part 的工作原理

::part() 伪元素允许开发者选择影子树内已通过 part 属性暴露的元素。

由于我们知道 ion-select 暴露了一个 placeholder 部分用于在未选择值时样式化文本,我们可以按以下方式自定义它:

ion-select::part(placeholder) {
color: blue;
opacity: 1;
}

使用 ::part 进行样式化允许更改该元素接受的任何 CSS 属性。

除了能够定位 part 之外,伪元素也可以在没有显式暴露的情况下进行样式化:

ion-select::part(placeholder)::first-letter {
font-size: 22px;
font-weight: 500;
}

Parts 也适用于大多数 伪类

ion-item::part(native):hover {
color: green;
}
备注

厂商前缀伪元素结构伪类存在一些已知限制。

Ionic Framework 部件

Ionic Framework 组件的所有已暴露部分都可以在其 API 页面的 CSS 阴影部分标题下找到。要查看所有组件及其 API 页面,请参阅组件文档

要拥有部分,组件必须满足以下条件:

  • 它是一个 Shadow DOM 组件。如果是 Scoped 或 Light DOM 组件,子元素可以直接定位。如果组件是 Scoped 或 Shadow,会在其组件文档页面上通过名称列出。
  • 它包含子元素。例如,ion-card-header 是一个 Shadow 组件,但所有样式都应用于宿主元素。由于它没有子元素,因此不需要部分。
  • 子元素不是结构性的。在某些组件中,包括 ion-title,子元素是用于定位内部元素的结构性元素。我们不建议自定义结构性元素,因为这可能导致意外结果。
备注

我们欢迎对额外部分的建议。在请求部分时,请在 GitHub 上创建一个新的 issue,并尽可能提供详细信息。

已知限制

浏览器支持

CSS 阴影部分在所有主要浏览器的最新版本中都得到支持。但是,某些旧版本不支持阴影部分。在应用中实现部分之前,请验证浏览器支持是否满足要求。如果需要支持旧版本浏览器,我们建议继续使用 CSS 变量进行样式化。

厂商前缀伪元素

厂商前缀伪元素目前不受支持。例如,任何 ::-webkit-scrollbar 伪元素:

/* 不起作用 */
my-component::part(scroll)::-webkit-scrollbar {
background: green;
}

有关更多信息,请参阅 GitHub 上的这个问题

结构伪类

大多数伪类都支持 parts,但结构伪类不支持。以下是不起作用的结构伪类示例。

/* 不起作用 */
my-component::part(container):first-child {
background: green;
}

/* 不起作用 */
my-component::part(container):last-child {
background: green;
}

链式 Parts

::part() 伪元素不能匹配额外的 ::part()

例如,my-component::part(button)::part(label) 不匹配任何内容。这是因为这样做会暴露比预期更多的结构信息。

如果 <my-component> 的内部按钮使用类似 part="label => button-label" 的方式将按钮的内部部分转发到面板自己的 part 元素映射中,那么像 my-component::part(button-label) 这样的选择器将只选择该按钮的标签,忽略任何其他标签。