:: 用于 shadowDOM 插槽中嵌套子项的插槽 CSS 选择器

Men*_*ndy 17 css css-selectors web-component shadow-dom custom-element

CSS::slotted选择器选择<slot>元素的子元素。

但是,当尝试选择像 with ::slotted(*), ::slotted(*) *, or那样的孙子时,选择::slotted(* *)器似乎没有生效。

class MyElement extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({mode: 'open'})
    shadowRoot.innerHTML = `
      <style>
        ::slotted(*) {
          display: block;
          border: solid blue 1px;
          padding: 3px;
        }
        ::slotted(*) span {
          display: block;
          border: solid red 1px;
          padding: 3px;
        }
        ::slotted(* span) {
          display: block;
          border: solid green 1px;
          padding: 3px;
        }
      </style>
      <slot></slot>
    `;
  }
}
customElements.define('my-element', MyElement);
Run Code Online (Sandbox Code Playgroud)
<my-element>
  <p>
    <span>Test</span>
  </p>
</my-element>
Run Code Online (Sandbox Code Playgroud)

请注意跨度如何没有边界。

这是预期的行为吗?我无法为此找到具体的文档。

如果是,有没有办法解决这个问题?

Dan*_*man 34

样式 :: shadowDOM 中的槽元素

TL; 博士


背景

是的,::slotted()不对嵌套元素设置样式是预期行为。

这个术语slotted是违反直觉的,
它意味着元素 lightDOM 被移动到 shadowDOM

开槽的 lightDOM不会移动,它仍然......隐藏......在 lightDOM 中
,内容(如果开槽)被反射<slot></slot>

或来自Google 开发者文档

, .
'; .

我使用术语反射而不是渲染,因为渲染意味着您可以shadowDOM 中访问它。
你不能,因为开槽内容不是shadowDOM ......仅反映从lightDOM。


为什么 :slotted 的功能有限

尝试了更高级的 shadowDOM 样式。

WebComponents 版本 0 (v0) 具有<content>::content;但它已从规范中删除:https :
//developer.mozilla.org/en-US/docs/Web/HTML/Element/content

W3C 标准讨论的主要内容
(@hayatoito(谷歌团队)在这里这里)是:

所以在 V1 中,我们有:slottedhttps : //developer.mozilla.org/en-US/docs/Web/CSS/ :: slotted


添加 #1:如果 ::slotted 允许复杂选择器的性能

来自 Mozilla 开发者 Emilio:

来源:https : //github.com/w3c/webcomponents/issues/889

性能问题是它增加了每个节点需要去寻找影响它们的规则的子树的数量。

现在的逻辑是这样的:如果你被打入了插槽,根据需要遍历你的插槽并在它们的影子树中收集规则。这是代码 这很好,因为元素样式的复杂性直接取决于您正在构建的阴影树的复杂性,并且它只影响开槽节点。

如果您想允许组合子经过时隙,那么每个节点都需要查看其祖先链和前兄弟链,并查看其中的哪些是时隙的,然后对它们的所有时隙执行该过程。然后,最重要的是,您还需要更改一般选择器匹配代码,以便如果您不在正确的影子树中,则不包含带槽选择器的选择器将不匹配。

这是您为所有元素支付的成本,无论您是使用 Shadow DOM 还是 ::slotted,而且可能只是不会飞。


所以由于性能问题

:slotted( S ) 获得有限的 CSS 选择器功能:

  • ? 它只需要简单的 S 选择器。 --> 基本上任何有空格的东西都不起作用

  • ? 它只针对 lightDOM 'skin'。--> 也就是说,只有一级

<my-element>
  <h1>Hello World</h1> 
  <p class=foo>
    <span>....</span>
  </p>
  <p class=bar>
    <span>....</span>
  </p>
</my-element>
Run Code Online (Sandbox Code Playgroud)
  • ::slotted(h1)::slotted(p)作品

  • ::slotted(.foo) 作品

  • ::slotted(span)(或任何更深的东西)将不起作用(不是“皮肤”元素)

注意: ::slotted([Simple Selector])确认Specificity 规则,
但(简单)不会增加lightDOM皮肤选择器的权重,因此永远不会获得更高的Specificity。在某些(罕见的)用例中
可能需要!important

 <style>
  ::slotted(H1) {
    color: blue !important;
  }
 <style>
Run Code Online (Sandbox Code Playgroud)

样式插槽内容

另请参阅:将更多深度选择应用于 :host CSS 伪类

#1 - 样式 lightDOM

<span>隐藏在lightDOM,所作的任何更改也将继续反映开槽表示。

这意味着您可以在主 DOM 中使用 CSS应用您想要的任何样式
(或者如果您包装<my-element>在一个父 shadowDOM 容器中)

 <style>
  my-element span {
    .. any CSS you want
  }
 <style>
Run Code Online (Sandbox Code Playgroud)

#2 - (解决方法)将 lightDOM 移动到 shadowDOM

如果您使用以下命令lightDOM移动shadowDOM:this.shadowRoot.append(...this.childNodes)

你可以在 shadowDOM<style>标签中做你想要的所有样式。

注意:您现在不能使用<slot></slot>:slotted()了。
<slot>s仅适用于从 lightDOM反射的内容。

有关元素将自身包裹在额外的 shadowDOM 层中的示例,
因此没有CSS 溢出,并且<slot>s可以使用,请参阅:

#3 - ::part(阴影部分)

这是一种不同/强大的 shadowDOM 内容样式方式:

Apple 终于在 2020 年 3 月的 Safari 13.1 中实现了 shadowParts

看:

笔记! ::part样式shadowDOM
<slot></slot>内容保留在lightDOM 中


参考

请注意:可能包含 v0 文档!


示例:使用插槽作为路由器

更改 buttonclick 上的插槽名称并反映 lightDOM 中的内容:

<my-element>
  <h1>Hello World</h1> 
  <p class=foo>
    <span>....</span>
  </p>
  <p class=bar>
    <span>....</span>
  </p>
</my-element>
Run Code Online (Sandbox Code Playgroud)

  • 对于该绩效评论,没有提供任何证据。我们需要看到数字。网络中有很多“慢”的 API,但如果正确使用它们并不都是坏事。 (2认同)
  • @trusktr 是的……性能不佳是删除功能的一个糟糕原因。例如:动画宽度的表现非常糟糕,但这取决于开发人员是否这样做。 (2认同)
  • @FeldsLiscia 确实如此。在大多数情况下,即使在最慢的低端手机上,甚至可能在智能手表上,这样的动画也能正常工作。为一两个事物设置动画与为 100 或 1000 个事物设置动画不同。开发人员应该有选择,并且知道何时使用它们。文档在这里很重要。 (2认同)