最近,我在听一个著名的播客,很棒的主持人正在谈论 Web 组件,列出了各种 Web 组件规格和功能的所有好的、坏的和丑陋的部分。
向 Chris Coyier 和 Dave Rupert 致敬,感谢他们的完全公平的剧集和精彩的对话。在这里收听该剧集:
商店脱口秀
任何人,在那一集的深处,我惊讶地发现 CSS Parts 进入了坏人列表,尽管我可以看到人们可能认为它们不是最好的一些原因。我碰巧认为 CSS 部分不仅非常好,而且实际上将我们所有使用它们的人从一个场景中拯救出来,这种场景比无法像无法完全设置 Web 组件影子根中的每个元素的样式更烦人和令人沮丧你想要的。
让我解释一下,但首先了解更多背景!
我无法明确验证以下所有内容是否属实,但我个人的观点(在过去几年的日常工作中编写、使用和帮助规范 Web 组件功能时产生的)是,现有的 Web 组件规范和功能都是为了解决“第三方组件”用例而设计的。也就是说,Web 组件旨在支持非常具体的情况:组件作者创建一个工具,其他消费者可以从互联网下载并在他们的应用程序中使用该工具。
我觉得,如果您通过“第三方组件”用例的角度来看待 Web 组件功能,那么规范编写者和浏览器实现者所采取的许多方法都非常有意义。以shadow dom风格封装的严重性为例。如果您将一个组件从互联网上拉到您的应用程序中,那么不必担心该组件的 css 会以某种方式破坏您的页面之一,这不是很棒吗?不必关心您没有编写的组件的内部结构,并将该组件视为黑盒并通过定义良好的 api 表面与其进行交互,这不是很棒吗?
理解 Web 组件如何设计工作的大部分问题是,自从创建 Web 组件规范以来,行业已经发生了变化,如今我们在应用程序中使用的 99% 的组件都不是来自外部来源。如今,当我们想到组件时,大多数时候我们想到的是我们或我们的团队编写的“第一方组件”,而不是互联网上的某个人。我们在应用程序中不会使用那么多外部组件,因此主要针对该用例设计的 Web 组件 API 对我们来说似乎很奇怪,特别是当我们还尝试使用 Web 组件为自己创建第一方组件时。
因此,对于我在本文中要说的所有其他内容,假设我指的是“第三方组件”情况。想象一下,我正在谈论的组件是您下载的一个 npm 包,并且有一个 GitHub 自述文件和补丁说明等,但您(或您的团队)没有为您自己的应用程序自己编写它。
CSS 部件对于您为自己或团队编写并完全控制的样式组件来说并不是一个很好的界面。
精心设计的组件有多种不同的交互方式。优秀的 Web 组件具有用于自定义 HTML 的插槽、用于自定义主题的 CSS 自定义属性以及用于自定义样式的 CSS 部件。 Shop Talk Show 的朋友们讨论了 CSS 部件,背景是它们对于自由形式样式来说很笨重,但我不会那样考虑 CSS 部件。我将它们视为组件的另一个公共 API 表面,与属性或特性非常相似。人们通常不太担心无法为从互联网上获取的组件创建自定义属性或属性。我认为CSS Parts 是同样的想法。组件作者指定内部模板的各个部分可以按照您想要的任何方式“设置样式”。因此,能够为 Shadow dom Web 组件中的每个内部元素设置样式并不一定是一种期望。
还有谁比组件作者更了解某个复杂模板的哪些部分可以应用任何样式呢?如果您从互联网上获取一个组件只是为了转身并重写所有样式,可能会在此过程中破坏可访问性等,那么您为什么首先安装该组件呢?我得到了许多人所提倡的“我知道我在做什么”阴影根选择器的吸引力,但在下一节中,我将阐明为什么我认为有一个定义的样式 API 表面与内部 DOM 结构断开连接实际上是令人惊奇的,应该庆祝它帮助我们所有开发人员不发疯。
提示老式电影预告片声音
让我们跳入一个想象的世界,其中 CSS 部件不存在,并且存在一些“我知道我在做什么”选择器(为了怀旧,我们将其称为 /deep/),并且是存在的“方式”您应该设置某些影子根 Web 组件的内部 DOM 模板的样式。
你的应用程序需要一个这样的组件,所以你去下载一个 npm 包
npm i some-awesome-package@1.2.3
并在您的应用程序中包含以下 HTML:
<some-awesome-component></some-awesome-component>
Some Awesome Component 组件中有一个默认为红色的 div,并且不使用任何 CSS 自定义属性。一开始,红色 div 完全没问题!
但随后您决定需要将红色 div 的颜色更改为 rebeccapurple。所以你写这个CSS:
@layer my-overides { some-awesome-component /deep/ div.the-red-div { background: rebeccapurple; } }
the-red-div 对于一个类来说是一个糟糕的名字,但是嘿,没有人关心 Shadow dom Web 组件的内部结构,对吧?它们不能与外界发生冲突,因此组件作者可以根据需要编写糟糕的类名。
因为我们处于 /deep/ 存在的想象世界中,所以一切正常!红色 div 现在是紫色的,一切都是 Coolio。
你忽略了我们大脑中微小的认知失调,即 .the-red-div 的颜色不是红色。那是明天的问题。
甜甜的!
然后组件作者添加一个功能并发布补丁。
您正忙着运送,一路上,您重新安装了一个不相关的软件包,并拉取了一些很棒的组件的最新补丁,红色 div 又回来了!
什么给了?你去搜索补丁说明,你会发现:
## 1.2.4 - [a987s83] Added cool button, fixed a11y issues
看起来不错,为什么 CSS 损坏了?变更日志注释没有任何线索。所以你浏览了最新的几篇 PR,并没有看到任何让你感兴趣的内容。
因此,您启动应用程序并检查影子根,红色 div 是一个 。现在!组件作者意识到他们的类名 the-red-div 应该更通用,并将其更改为 colorful。
好的,所以你将 css 编辑为:
@layer my-overides { some-awesome-component /deep/ .colorful { background: rebeccapurple; } }
一切又恢复正常了!
然后作者会在下周发布另一个补丁。
跳回现实世界
看到模式,因此直接选择器访问您不拥有或控制的内部模板时出现问题?
不可避免地,内部模板的更改将超出您(组件使用者)的控制。不可避免地,这些变化将以一种几乎看不见的方式发生,而无需手动或使用不稳定的视觉回归测试工具对正在运行的应用程序的每一部分进行目视检查。如果您使用来自互联网的组件,那么就会有某种合同。组件作者拥有 Shadow dom,而您(消费者)拥有 :host 元素(您编写的代码中的
有趣的事实是,在 JS 中对 DOM 元素进行直接 Shadow dom querySelectors 时也会发生这种脆弱性。如果您的应用程序依赖于某些元素来始终存在,那么它就不会存在。如果您查询不受您控制的 DOM,有一天某些元素将不存在。它要么是不同的元素,要么具有不同的类/属性/id。
因为 CSS 部件是简单的字符串,本身不是 DOM 元素,所以使用它们可以保护您的应用程序免受脆弱代码的影响。第三方作者永远不会测试某个 div 永远是一个 div。但是,如果他们创建 CSS 部件,他们就知道他们正在为该组件创建一个公共 API,如果不进行重大更改,就无法删除或更改该 API。如果您使用 CSS 部件而不是直接查询 Shadow DOM,那么组件作者可以在 Shadow DOM 中移动该 CSS 部件,并且您的应用程序代码不会中断。
此外,由于 CSS Part 名称暗示了关系、概念和功能,因此组件作者很难重构组件以使 CSS Part 实质上改变其含义。因此,除了知道使用代码的 CSS 部件不会因为组件作者在没有通知您的情况下进行更改而中断之外,您还可以合理地确定 CSS 部件与整体的关系始终是同一类事物成分。因此,即使组件随着时间的推移而演变,您应用于该部分的样式也将相当确定始终对该部分“有意义”。
我看到了一些来自非常聪明且有价值的行业人士关于 CSS 部件的痛苦的评论,并且通过选择器添加直接的 Shadow dom 访问会更加方便。如果随着时间的推移一切都没有改变,我会全心全意地同意。但由于组件确实会随着时间的推移而发生变化,我敢说直接访问影子 DOM 会比记住哪些 CSS 部件可供使用更痛苦。
每当讨论如何跨越“应用程序”和组件内的 Shadow dom 之间的边界时,我总是提倡使用一些命名的结构契约方法,例如 CSS Parts,而不是直接选择器访问。在我看来,任何认为 CSS 部件笨重且糟糕的人都不必在整个应用程序中寻找影子根模板在他们不知情的情况下更改的所有位置:)
CSS 部件很棒,当您使用它们时,即使您 100% 是一位出色的开发人员并且您知道自己在做什么,您也 100% 不希望可能需要调整所有自定义 CSS 带来的痛苦每次您使用的组件出现补丁时,您都会编写此内容。您肯定知道自己在做什么,但我们所有人都希望防止我们的应用程序随机损坏,而这就是直接影子 DOM 样式所要做的。 “我知道我在做什么”选择器肯定会让您的样式正常工作,但只有在您从不更新样式的包版本时才能保证正常工作。如果您确实更新了版本,则每次都必须留意所有这些“我知道我在做什么”样式。
我认为这是浪费我们宝贵的时间。只需使用 CSS 部件并鼓励组件开发人员将它们添加到他们编写的组件中即可。
以上是CSS Parts 将你从噩梦中拯救出来的详细内容。更多信息请关注PHP中文网其他相关文章!