Safari 13.1刚刚提供了对CSS Shadow Parts的支持。 这意味着Chrome,Edge,Opera,Safari和Firefox现在支持::part()
选择器。 我们将看到为什么它有用,但首先回顾一下影子DOM封装…
影子DOM封装的好处
我在giffgaff工作,多年来,我们有各种各样CSS代码,这些代码已经由许多不同的人以许多不同的方式编写。 让我们考虑一下这可能有问题。
命名冲突
类之间的命名冲突很容易在CSS中出现。 一个开发人员可能会创建一个类名,例如.price。 另一位开发人员(甚至同一个开发人员)可能在不知道的情况下使用相同的类名。
CSS不会在这里警告您任何错误。 现在,任何具有此类HTML元素都将收到用于两种完全不同的内容的样式。
Shadow DOM解决了此问题。 CSS-in-JS库(例如Emotion和样式化组件 )也通过生成随机类名(例如.bwzfXH
以不同的方式解决了此问题。 这确实有助于避免冲突! 但是,CSS-in-JS不会阻止任何人以其他方式破坏您的组件。 例如…
基本样式和CSS重置
可以使用HTML元素选择器(例如<button>
和<div>
来应用样式。 这些样式可能会破坏组件。 Shadow DOM是唯一提供( 几乎 )完全封装的东西-您可以放心,即使在杂乱的重要散布代码库中,组件也看起来一样,因为每个组件都被封装了。
/* This will have no effect on buttons inside shadow DOM */
button { background-color: lime !important; }
我不会说以这种方式设置元素的样式是一种好习惯,但这确实发生了。 即使这样,这些样式也不会对影子DOM产生影响。
值得一提的是,可继承样式一样color
, font
和line-height
仍然继承了阴影DOM。 为防止这种情况,请在具有更好的浏览器支持后使用all: initial
,最好使用all: revert
。
让我们看一个直接应用于HTML元素CSS常见示例。 考虑一下Eric Meyer的重置代码:
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
如果我们正在使用的组件利用用户代理的边距和填充的默认值怎么办? 由于有效清除了这些默认设置,因此此重置可能会导致其显示为损坏。
Shadow DOM是避免这些问题的一种方法。 Shadow DOM使我们完全有信心组件能够按预期呈现,而不管其最终使用什么代码库。同样,仅用于组件的代码都不会无意间影响其他任何事物-所有这些都无需诉诸繁琐的类命名约定。 Shadow DOM提供了某种其他方式无法实现的封装级别。
封装很棒,但是我们也希望我们的组件具有主题性和可定制性。 ::part
选择器使事情变得更加容易。
用:: part()设置阴影DOM的样式
到目前为止,CSS从影子DOM外部修改自定义元素样式的唯一方法是使用CSS自定义属性。 在只希望允许有限更改的严格设计系统中,这可能是理想的。 如果您希望组件具有更多用途,那么就会出现问题。 您要使用样式设置的每个 CSS属性都必须使用自定义属性进行定义。 只是声音听起来很乏味。
如果我们想根据伪类(例如:hover
对组件进行不同的样式设置,则情况会更加复杂。 基本上,我们最终会获得大量的自定义属性。 让我们看一下Ionic的示例, Ionic是一组Web组件的开源。 只需查看Ionic按钮组件上定义的所有自定义属性即可 。
来吧,我等。
我计算了23个自定义属性。 不用说,这并不理想。
这是一个使用::part()
设置元素样式的示例。
在这支笔中,我只是更改了color
, border
和background-color
属性,但是我可以使用我想要的任何内容而不受已定义的自定义属性的限制。 注意,我还可以使用伪类(例如:hover
和:focus
来设置零件的不同状态样式。
该按钮示例中的整个组件都将进行样式设置,但是,如果您的Web组件由多个HTML元素组成,则只能将组件的选定部分进行这种样式设置,因此命名为::part
。 这将阻止组件的用户设置阴影树中任何任意元素的样式。 组件作者有责任公开他们明确想要的组件部分。 组件的其他部分可以在视觉上保持一致,也可以使用自定义属性以将自定义性降至最低。
那么,如何为自己的组件设置呢? 让我们看看使用::part
使Web组件的某些元素符合样式要求。 我们要做的就是在要公开的元素上添加part属性。
<div part="box">...</div>
<button>Click me</button>
在此示例中,div可使用CSS的全部范围进行自定义-可以更改任何CSS属性。 但是,该按钮已锁定-除组件作者外,其他任何人都无法从视觉上更改该按钮。
与HTML元素可以具有多个类的方式相同,一个元素可以具有多个部件名称:
<div part="box thing">...</div>
这就是::part
:通过公开元素的“部分”,我们可以在使用Web组件时提供一些灵活性,同时在其他领域进行保护。 无论是您的设计系统,组件库还是您拥有什么,CSS Shadow Parts都已成为主流,这为我们提供了另一个令人兴奋的工具。
翻译自: https://css-tricks.com/styling-in-the-shadow-dom-with-css-shadow-parts/