发布于 2026-01-06 1 阅读
0

Shadow DOM 的特性及其利用方法 什么是 Shadow DOM? 1 - 这里的继承机制是怎样的? 解释原因。 2 - 能否为宿主元素设置样式? 解释原因。 3 - 是否应用了 CSS 变量? 解释原因。 4 - 子节点会发生什么变化? 解释原因。 5 - 能否只为部分元素设置样式? 解释原因。 关闭 更多信息

暗影领域(Shadow DOM)的特性以及如何利用它们

什么是 Shadow DOM?

1 - 这里的继承是如何运作的?

回答

为什么?

2 - 你能为主持人设计造型吗?

回答

为什么?

3 - 是否应用了 CSS 变量?

回答

为什么?

4 - 子节点会发生什么变化?

回答

为什么?

5 - 能否只对部分部件进行造型?

答案 5

为什么?

关闭

更多信息

免责声明:

在本文中,我将把“普通”DOM称为“轻量级DOM”,以便清楚地表明我何时在谈论它。

什么是 Shadow DOM?

虽然 Shadow DOM 被认为是构成 Web Components 的核心标准之一,但
实际上它已经在浏览器中存在相当长一段时间了,因为原生 HTML 元素(例如<video>
<div>)使用它,只是在它被纳入 Web Components 标准之前,开发人员无法使用它。

现在Edge浏览器基于Chromium内核,所有Web组件标准,包括Shadow DOM,都可以在所有现代浏览器中使用啦!!🎉

Shadow DOM 的全部意义在于,它允许我们创建与 Light DOM 隔离的 DOM 树
,但可以将这些 DOM 树附加到 Light DOM 上并与其一起渲染。

我知道这听起来有点令人困惑,所以这张图或许能帮助更好地理解:

影子 DOM 可视化

来源:《使用 Shadow DOM》,作者:Mozilla 贡献者

这种隔离是 Shadow DOM 的关键特性,它解决了其他方法无法真正解决的几个问题:

  1. Shadow DOM 内部的节点无法通过类似这样的方式访问document.querySelector(),因此可以防止其他脚本进行不必要的更改。
  2. Shadow DOM 中的所有 CSS 都限定在其作用域内,这带来了一些很大的好处:
    1. Shadow DOM 中的样式不会泄露到 Light DOM 中。
    2. Light DOM 中的样式不会影响到 Shadow DOM*
    3. 这两个功能让你能够使用像 `<select>`button或 ` <select>` 这样非常简单的选择器#someid,而不用担心任何问题,这就是我们说 Shadow DOM 修复 CSS 的最大原因,一切都有其自身的作用域。

现在,您可能已经注意到,我在提到 Light DOM 样式不会渗透到 Shadow DOM 时,加了一个星号。

你看,如果 Shadow DOM 无法通过 Light DOM 进行样式设置,那么对于主题化和轻量级自定义等许多常见用例来说,它的限制性就太大了。

这就是为什么在某些情况下可以从 Light DOM 对 Shadow DOM 内容进行样式设置的原因。

与许多 CSS 相关的内容一样,这些内容仅靠阅读很难理解,因此我将在本文的其余部分采用类似测验的方式进行讲解。

1 - 这里的继承是如何运作的?

这是我们第一个 Shadow DOM 的标记:



<style>
  .some-class {
    font-family: Arial;
    font-size: 14px;
    color: blue;
  }
</style>

<div>
  This is some text
</div>
<div class="some-class">
  And here's some more text
</div>


Enter fullscreen mode Exit fullscreen mode

这就是光之领域



<style>
  .container {
    font-family: Helvetica;
    font-size: 16px;
    color: green;
    padding: 2em;
  }

  .container .some-class {
    color: red;
  }
</style>
<div class="container">
  <!--
  The Shadow DOM from the previous snippet is
  in this web component
  -->
  <question-one></question-one>
</div>


Enter fullscreen mode Exit fullscreen mode

你觉得最终效果会如何?别剧透哦😉。

回答

为什么?

默认情况下,Shadow DOM 内部的节点没有特殊样式,因此继承属性(例如 `style`
font-family或 `style` color)将从 Shadow DOM 的祖先继承其值。

现在,正如你所看到的,some-class我们实际上定义了font-family,,,font-size因此color该部分不会继承样式。

如果你注意到.container .some-classLight DOM 中的选择器基本上是无用的,因为它试图直接影响 Shadow DOM 中的节点,这是不允许的,那么你会得到额外的分数。

2 - 你能为主持人设计造型吗?

以下是 Shadow DOM:



<style>
  /*
  This selector basically applies to the root
  of our shadow DOM
  */
  :host {
    display: block;
    width: 30px;
    border: 1px dotted black;
  }
</style>

<div>1</div>
<div>2</div>
<div>3</div>


Enter fullscreen mode Exit fullscreen mode

这是 Light DOM:



<style>
  .some-class {
    display: flex;
    flex-flow: row-reverse;
    width: 100%;
    border: 1px solid red;
  }
</style>
<question-two></question-two>
<question-two class="some-class"></question-two>


Enter fullscreen mode Exit fullscreen mode

你觉得最终效果会如何?准备好了吗?

回答

为什么?

与应用于子节点的样式不同,Shadow DOM 中的主机级样式可以从 Light DOM 中覆盖。

基本上,你直接为宿主定义的任何东西都只不过是默认样式,所以如果你真的想强制执行某种样式,你可能需要添加一个容器节点作为子节点并为其设置样式。

3 - 是否应用了 CSS 变量?

以下是 Shadow DOM:



<style>
  div {
    color: var(--my-color, blue);
  }
</style>

<div>
  Some text
</div>


Enter fullscreen mode Exit fullscreen mode

这是 Light DOM:



<style>
  .custom-color {
    --my-color: red;
  }
</style>

<question-three></question-three>
<question-three class="custom-color"></question-three>


Enter fullscreen mode Exit fullscreen mode

这个颜色会怎么样?

回答

为什么?

CSS 自定义属性(或大多数人称之为 CSS 变量)是少数几种可以自由设置 Shadow DOM 中节点样式的东西之一。

当然,就像这个例子一样,Shadow DOM 中使用的样式必须定义它要使用哪些变量以及在哪里使用,但这是一种在关键点上提供自定义的简单方法。

如需了解更多关于 CSS 变量的信息,本文可作为入门参考。

4 - 子节点会发生什么变化?

准备好回答最后一个问题了吗?以下是 Shadow DOM:



<style>
  /*
  the ::slotted(selector) selector applies to
  any nodes appended in the indicated slot
  that match the given selector
  */
  header ::slotted(*) {
    text-decoration: underline;
  }
  article ::slotted(div.special) {
    color: turquoise;
  }
</style>

<section>
  <header>
    <h3><slot name="header">Default Header</slot></h3>
  </header>
  <article>
    <slot></slot>
  </article>
</section>


Enter fullscreen mode Exit fullscreen mode

这是 Light DOM:



<style>
  .some-class .header {
    color: red;
  }

  .some-class div {
    color: mediumvioletred;
  }
</style>

<question-four>
  <div>1</div>
  <div class="special">2</div>
  <div>3</div>
</question-four>

<question-four class="some-class">
  <div>4</div>
  <div class="special">5</div>
  <div>6</div>
  <span class="header" slot="header">
    Second Element Header
  </span>
</question-four>


Enter fullscreen mode Exit fullscreen mode

这个需要解决的问题比较多,所以请慢慢来,你觉得最终效果会如何?

回答

为什么?

如果你是第一次接触 Shadow DOM,没看懂我不会怪你,但请耐心听我解释,我会尽力解释清楚。

你看,在 Shadow DOM 中有一个特殊的<slot>标签,它的作用基本上是说明该元素的子元素将被附加到模板的哪个部分。

如果你在 React 中使用过childrenslots 或在 Vue 中使用过 slots,你可能已经熟悉这个概念了(Vue 的 slots 就是基于这个标准的)。

现在,在 Shadow DOM 中定义的样式中,我们可以尝试使用::slotted()选择器将样式应用于通过插槽添加的子元素。

但正如你所见,这与前面几个问题中宿主级样式的工作方式非常相似。应用的样式::slotted()基本上也是默认样式,它们会与来自 Light DOM 的样式合并,但 Light DOM 样式的优先级更高。

5 - 能否只对部分部件进行造型?

最后一个问题!!准备好了吗?这就是影子领域:



<style>
  :host {
    display: flex;
  }
  img {
    width: 64px;
    height: 64px;
  }
  div {
    font-family: Arial;
    color: seagreen;
  }
</style>

<img part="avatar" src="https://via.placeholder.com/64x64.jpg?text=Avatar" />
<div part="name">
  Some Name
</div>


Enter fullscreen mode Exit fullscreen mode

这是 Light DOM:



<style>
  question-five.custom-part::part(avatar) {
    border-radius: 50%;
  }

  question-five.custom-part::part(name) {
    font-family: Verdana;
    color: mediumpurple;
  }
</style>

<question-five></question-five>
<question-five class="custom-part"></question-five>


Enter fullscreen mode Exit fullscreen mode

最后再问一遍,这部分内容将如何渲染?

答案 5

为什么?

现在我们进入了前沿领域,与前四个问题的内容在所有现代浏览器中都可用不同,最后一个问题目前在 Safari 中还不可用(它可能很快就会推出,因为它在技术预览版中,而且在我的测试中运行良好),但它在所有基于 Chromium 的浏览器(Chrome、Edge、Opera 等)和 Firefox 上都可用。

更新:截至 2020 年 10 月,Safari 已实现此标准,因此现在它适用于所有现代浏览器!

在这个演示中,我们使用了 Shadow Parts 标准,顾名思义,它允许我们在 Shadow DOM 中声明“部件”,然后可以使用::part()伪元素从 Light DOM 中设置这些部件的样式。

您现在可能已经看出来了,阴影部件的工作方式与插槽和宿主级样式的工作方式类似,因此使用::part()浅色 DOM 样式设置的属性将具有最高优先级,而使用阴影 DOM 设置的样式将作为备用方案。

关闭

Shadow DOM 是 Web 标准中非常强大的部分,但它确实有一些乍一看并不明显的怪癖。

我希望这个小测验能帮助你更好地理解 Shadow DOM 的工作原理,以及如何在使用和创建自己的 Web 组件时(甚至只是单独使用 Shadow DOM)充分利用它。

更多信息

https://developers.google.com/web/fundamentals/web-components/shadowdom
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM

文章来源:https://dev.to/alangdm/the-quirks-of-shadow-dom-and-how-to-take-advantage-of-them-4cd1