样式化 Web 组件

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 提供适合您旅程每个阶段的云产品。立即开始使用 价值 200 美元的免费积分!

这让我困惑了一阵子,所以趁着记忆犹新,我把它写下来。仅仅因为您使用的是 Web 组件,并不意味着它的样式完全是孤立的。Web 组件中可能包含与网站其余部分一样正常样式化的内容。 就像这样

查看 CodePen:具有全局样式的 Web 组件(因为没有 Shadow DOM),作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

<whats-up> 元素通过将点击处理程序附加到其内部的 <button> 来隔离其 JavaScript 驱动的功能。但是,该按钮的样式来自应用于该页面的 全局 CSS

将模板移到 Web 组件内部

但假设我们将该 <button> 移到 Web 组件中,以便我们可以单独使用 <whats-up>。我们可以通过 .innerHTML‘ing 自定义元素来做到这一点

查看 CodePen:具有全局样式的 Web 组件(因为没有 Shadow DOM),作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

同样,完全由全局 CSS 样式化。酷。这可能是可取的。它也可能不可取。也许您正在寻找 Web 组件来为您隔离样式。

Shadow DOM 化模板

Web 组件可以通过 Shadow DOM 来隔离样式(并抽象化 HTML 实现)。这是同一个组件,使用 Shadow DOM 代替

查看 CodePen:具有本地样式的 Web 组件,作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

请注意,功能仍然有效(尽管我们不得不通过 shadowRoot 进行 querySelector),但我们完全失去了全局样式。Shadow DOM 边界(shadow root)阻止样式进出(有点像 iframe)。

Shadow Root

据我所知,没有全局方法可以穿透该边界,因此如果您想引入样式,您必须将它们引入模板。

将样式(内联)移到 Web 组件内部

查看 CodePen:具有本地样式的 Web 组件,作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

如果您既想真正使用 Shadow DOM,又想使用全局样式,那么这将非常令人讨厌。有趣的是,Shadow DOM 有一种用于打开和关闭的“模式”,用于允许或禁止 JavaScript 进出,但 CSS 却没有。

如果是您,您可能需要 @import 任何可以使用的全局样式表,以便引入这些全局样式,并希望它们被缓存,并且浏览器以不造成重大性能影响的方式智能处理它们。

链接到外部样式

我将使用 CodePen 的直接链接到 CSS 功能,将来自 Pen 本身的样式导入到 Web 组件中

查看 CodePen:具有本地样式的 Web 组件,作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

显然,没有办法完全避免这种方式的非样式组件闪现现象,因此建议内联样式,直到出现这种情况。(嗯,查看 ::part)。

自定义属性会穿过 Shadow DOM

另一个需要了解的重要事项是,CSS 自定义属性会穿透 Shadow DOM!没错,它们确实会。您可以在 CSS 中选择 Web 组件并在那里设置它们

查看 CodePen:具有自定义属性的 Web 组件,作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

您通过 slot 指向的 HTML 可以全局样式化

所以如果你有像

<my-module>
  <h2 slot="header">My Module</h2>
</my-module>

而您在定义 Shadow DOM 的地方使用该标题

<div class="module">
  <slot name="header"></slot>
</div>

那么 <h2> 可以全局样式化,但 <div class="module"> 则不能。

查看 CodePen:slots 和样式化 Web 组件,作者 Chris Coyier (@chriscoyier) 在 CodePen 上。

::part 和 ::theme

我没有过多地研究这个,因为我认为这仍然是一个正在开发中的规范,但最终可能会在这里发挥重要作用。Monica Dinculescu 在她的文章 ::part 和 ::theme,一个 ::explainer 中详细介绍了它。

看起来像是一种进入 Shadow DOM 的方法,但只针对与之匹配的精确级别,不会更深。

<h4><x-foo>
  #shadow-root
    <div part="some-box"><span>...</span></div>
    <input part="some-input">
    <div>...</div> /* not styleable
</x-foo></h4>
x-foo::part(some-box) { ... }

/* nope */
x-foo::part(some-box) span { ... }