CSS 阴影部分即将到来!
Firefox 72 发布了一些新的 API,其中两个对 Web Components 用户来说是个好消息。第一个是FormDataEvent
基于事件的表单参与,之前仅在 Chromium 中可用。但今天我想重点介绍另一个自 Firefox 69 以来就已实现的功能:part
HTML 属性和::part
伪元素。
对于创建可自定义组件和设计系统的开发者来说, CSS Shadow Parts提案是最受期待的标准新增功能之一。它是一个全新的 API,用于从外部设置 Shadow DOM 中单个元素的样式。这使得特定 UI 小部件的单个实例能够略微改变外观——这是我们在实际应用中经常需要的功能。
与 CSS 自定义属性(例如 )不同,--primary-color
新的::part
伪元素赋予了我们梦寐以求的真正灵活性。在 Vaadin,我们早在 2017 年就采用了 CSS 阴影部分的概念,正如这篇关于主题的演讲中所解释的那样。现在,我们很高兴看到它::part
终于获得了跨浏览器支持。
历史
自定义伪元素(也称为 CSS Shadow Parts)的概念至少从 2015 年就开始讨论,但最终在 2017 年初达成一致,决定放弃CSS mixins 和@apply
提案(该提案从未在 Chrome 中发布),并改为实现::part
。三年后——对于 Web 标准来说并不算太久——我们将在 2020 年实现这一目标。
对于那些还记得Monica Dinculescu 的精彩解释的人来说,需要注意的是:规范从那时起已经发生了变化。现在 Fergal Daly 发布了更新版本。另外,今天我主要讨论的是::part
,因为::theme
,原始提案中的另一个伪元素 ,已经被推迟了。关于 的讨论正在进行中::theme
,其未来前景尚不明朗。
但其现状::part
看起来非常乐观。Chrome 从 73 版开始支持它,现在 Firefox 72 也支持它。Safari 已在技术预览版 94中实现了 CSS 阴影部分,目前仍在等待稳定版本的发布——与基于 Chromium 的 Edge 一样。所以现在是时候尝试::part
并学习如何在实践中使用它了。
用法
基本示例
根据规范编辑之一 Tab Atkins 的评论::part
,其目的是隐藏 Web 组件的内部细节,而仅公开组件作者明确想要公开的部分。
让我们直接来看示例。下面嵌入的 CodePen 提供了一个<vaadin-details>
使用 为自定义元素添加样式的示例::part
。这是一个简单的组件,它使用属性暴露了一些元素part
。
看起来就像经典的原生 CSS,不是吗?即使你在不支持 ::part
的浏览器中打开这个演示,也不会出现任何问题:组件仍然会保持其开箱即用的样式,并保持完整的功能。
在像这样的简单情况下使用 CSS Shadow Parts 非常省事。实际上,您只需part
在想要暴露的元素上添加 HTML 属性即可。这样,组件使用者就可以自行选择是否使用此 API。
::part
与伪元素一起使用
你可能注意到了,上面的示例演示了如何使用 CSS 选择器来设置详情切换按钮的样式::part(toggle)::after
。我们也可以::part
将此方法与任何其他伪元素结合使用。
如上面的 CodePen 所示,所有支持该功能的浏览器::part
都已支持此功能。不过,请不要期望它能与诸如 之类的非标准伪元素一起使用::-webkit-scrollbar
。
::part
与伪类一起使用
影子树中的元素经常需要的另一个功能是能够为某些状态添加样式,例如:hover
。我们可以使用 来实现它::part
——这也是它如何自然地融入我们习惯的 CSS 编写方式:
虽然其他用户操作伪类(如):focus
也可以与一起使用,但::part
规范明确指出不支持结构伪类(例如:first-child
、等等)。:nth-of-type()
:empty
路径转发exportparts
在某些情况下,我们可能需要暴露样式的部分位于嵌套组件中,该组件有自己的影子根。默认情况下,这是不可能的::part
,因为它不会递归遍历影子树。
不过,现在有exportparts
一个专门处理这种情况的属性。当影子树中的元素具有此属性时,其值定义了从该元素“导出”的部分,并且可以使用以下方式设置样式::part
:
截至目前,此功能仅作为“白名单”使用。曾有提案建议支持使用类似“通配符”的转发功能。然而,该功能目前尚未标准化,因此尚未在浏览器中实现。-*
特征检测
在某些情况下,你可能需要检测浏览器是否支持 CSS Shadow Parts,例如,加载.css
具有 fallback 样式的其他代码块或文件。这可以在 JS 中使用以下代码实现:
'part' in HTMLElement.prototype; // true if "part" is supported
没有跨浏览器的方法来检测::part
仅使用 CSS 的支持,因为@supports selector()
API 目前仅在 Firefox 中可用。
限制
虽然 CSS Shadow Parts 确实为我们带来了很大的灵活性,但它们在设计上仍然存在一些限制。这些限制与某些伪类有关,这些伪类在::part
属于它们之后就不再被允许使用。
::slotted()
与使用 Shadow DOM 的任何人所熟悉的伪元素相同,::part
不允许在复杂的选择器中使用,因此您不能使用它来设置兄弟节点或子节点的样式 - 只能设置其本身的部分。
另一个重要的限制是:之后无法使用类或属性选择器::part
——这些被视为实现细节。一种可能的解决方法是使用多部分方法。
伪:state()
类被设计用于配合使用::part
,它应该通过允许 CSS 来涵盖一些用例,例如::part(video):state(playing)
使用属性公开的自定义元素的样式part
。
记录
CSS Shadow Parts 可视为Web 组件公开的 CSS APIpart
。这意味着它们应该遵循语义版本控制——因此,删除或重命名任何属性都需要进行主要版本升级。
web -component-analyzer工具支持@csspart
JSDoc 注释,可用于记录自定义元素公开的 CSS Shadow Parts,并将其作为实验性 JSON 格式的一部分输出。
借助<api-viewer>
元素(我的个人项目),您可以从 JSON 生成 Web 组件 API 文档,包括 CSS 阴影部分。顺便说一下,<api-viewer>
它本身也可以使用 进行样式设置::part
。
了解更多
由于 CSS Shadow Parts 还是一个相对较新的 API,因此目前还没有太多示例。以下是一些可以::part
实际使用的地方:
-
Elix是 Jan Miksovsky 开发的一套实现常见 UI 模式的 Web 组件。Elix 推荐使用元素部件样式以及其他自定义元素外观的方法。
-
Chromium Web UI 元素。这些 Web 组件正在更新,将使用 CSS Shadow Parts 替代 CSS Mixins。您可以在Chrome 设置等多个地方看到它们。
-
Firefox UI。正如 Brian Grinstead 在最近的博客文章中提到的那样,使用 Web Components 重新构建 Firefox UI 的过程导致优先考虑 CSS Shadow Parts 支持以及其他相关功能。
-
web-platform-tests 套件。这个项目对于理解某些功能的工作原理非常有用。您可以检查结果,了解 CSS Shadow Parts 在最新浏览器版本中的工作方式。
-
Mozilla 开发者网络 (MDN) 已经提供了两篇关于
::part
伪元素和part
全局属性的文章。他们在项目中也有一个专门的示例web-components-examples
。
最后,如果您想了解仍在讨论的问题,请查看带有相应标签的CSSWG 问题跟踪器。
概括
CSS Shadow Parts 是一个新的 API,它已经可以在一些项目中使用,尤其是在那些可以接受优雅降级方法的情况下。因此,我强烈建议所有使用 Web 组件库、UI 工具包或设计系统的人都去评估part
一下exportparts
。