:: slotted CSS选择器,用于shadowDOM插槽中的嵌套子级 [英] ::slotted CSS selector for nested children in shadowDOM slot

查看:80
本文介绍了:: slotted CSS选择器,用于shadowDOM插槽中的嵌套子级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The CSS ::slotted selector selects children of the <slot> element.

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

however, when trying to select grandchildren like with ::slotted(*), ::slotted(*) *, or ::slotted(* *), the selector doesn't seem to take effect.

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);

<my-element>
  <p>
    <span>Test</span>
  </p>
</my-element>

请注意跨度如何无法获得边框.

Note how the span doesn't get the border.

这是预期的行为吗?我找不到为此的具体文档.

Is this expected behavior? I wasn't able to find concrete documentation for this.

如果是,是否有解决此问题的方法?

If yes, is there a way to work around this?

推荐答案

TL; DR

  • 插槽内容保留在lightDOM中,反映<slot>

::slotted(*)只能使用简单选择器

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

Yes, ::slotted() not styling nested elements is expected behavior.

术语slotted是违反直觉的,
这表示元素lightDOM已 移动 到shadowDOM

The term slotted is counterintuitive,
it implies element lightDOM is moved to shadowDOM

已插入插槽的lightDOM 未移动,它仍保留在lightDOM中. 内容被反映<slot></slot>

slotted lightDOM is NOT moved, it remains.. hidden.. in lightDOM
the content is reflected to a <slot></slot>

或者从 Google开发者文档中获取

从概念上讲,分布式节点似乎有些奇怪.
插槽实际上不会移动DOM;他们将其渲染到阴影DOM内的另一个位置.

Conceptually, distributed nodes can seem a bit bizarre.
Slots don't physically move DOM; they render it at another location inside the shadow DOM.

我使用 reflected 而不是 render ,因为 render 意味着您可以在 shadowDOM中访问它.您不能这样做,因为广告位内容不是 shadowDOM中...仅从lightDOM 反映.

I use the term reflected instead of render because render implies you can access it in shadowDOM. You can not, because slotted content isn't in shadowDOM... only reflected from lightDOM.

W3C标准讨论的主要内容(@hayatoito 此处此处)是:

The main takeway from the W3C standards discussions (@hayatoito here and here) is:

https://developer.mozilla.org/en -US/docs/Web/CSS/::开槽

来自Mozilla开发人员Emilio:

From Mozilla developer Emilio:

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

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

The performance issue is that it increments the amount of subtrees in which every node needs to go look for rules that affect to them.

现在的逻辑是这样的:如果您已放空槽,则遍历您的槽 并根据需要在其影子树中收集规则. 这是代码 这很好,因为样式元素的复杂性 直接取决于您所使用的阴影树的复杂性 建筑物,它只会影响开槽的节点.

Right now the logic goes like: if you're slotted, traverse your slots and collect rules in their shadow trees as needed. This is the code This is nice because the complexity of styling the element depends directly on the complexity of the shadow trees that you're building, and it only affects slotted nodes.

如果您想让组合器超出槽口,则每个节点都将 需要查看其祖先和上级兄弟链,并查看 将其中的一个插入插槽,然后对其所有插槽进行该过程. 然后,最重要的是,您还需要更改常规选择器匹配 代码,这样不包含空位选择器的选择器就不会 如果您不在正确的阴影树中,则匹配.

If you want to allow combinators past slotted then every node would need to look at its ancestor and prev-sibling chain and look at which ones of them are slotted, then do that process for all their slots. Then, on top, you also need to change the general selector-matching code so that selectors that do not contain slotted selectors don't match if you're not in the right shadow tree.

这是您为所有元素支付的费用,无论您是否 使用Shadow DOM或:: slotted,并且可能不会运行.

That's a cost that you pay for all elements, regardless of whether you use Shadow DOM or ::slotted, and is probably just not going to fly.

所以由于性能问题

:slotted( S )的CSS选择器功能受到限制:

  • ►它仅需要简单的S选择器.基本上任何有空格的东西都不起作用

    So due to performance issues

    :slotted( S ) got limited CSS selector functionality:

    • ► it only takes simple selectors for S. --> Basically anything with a space won't work

      ►它仅针对lightDOM 皮肤" . ->换句话说,只有第一级

      ► it only targets lightDOM 'skin'. --> In other words, only the first level

      • ::slotted(h1)::slotted(p)有效

      ::slotted(.foo)有效

      ::slotted(span)(或更深的内容)将不起作用(不是'皮肤'元素)

      ::slotted(span) (or anything deeper) will not work (not a 'skin' element)

      <my-element>
        <h1>Hello World</h1> 
        <p class=foo>
          <span>....</span>
        </p>
        <p class=bar>
          <span>....</span>
        </p>
      </my-element>
      

      解决方法

      解决方法#1-样式lightDOM

      <span>隐藏在lightDOM中,在那里所做的任何更改将继续反映为其带槽表示.

      workarounds

      workaround #1 - style lightDOM

      The <span> is hidden in lightDOM, any changes made there will continue to reflect to its slotted representation.

      这意味着您可以在主DOM中使用CSS 使用任何样式
      (如果您将<my-element>包装在其中,则为父shadowDOM容器)

      That means you can apply any styling you want with CSS in the main DOM
      (or a parent shadowDOM container if you wrapped <my-element> in one)

       <style>
        my-element span {
          .. any CSS you want
        }
       <style>
      

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

      Note: ::slotted([Simple Selector]) confirms to Specificity rules,
      but (being simple) does not add weight to lightDOM skin selectors, so never gets higher Specificity.
      You might need !important in some (rare) use cases.

       <style>
        ::slotted(H1) {
          color: blue !important;
        }
       <style>
      

      解决方法#2-将lightDOM移至shadowDOM

      如果使用appendChildappend(或insertBefore或cloneNode等)将lightDOM从lightDOM 移动到shadowDOM,则可以进行所需的所有样式.

      workaround #2 - move lightDOM to shadowDOM

      If you move lightDOM with appendChild or append (or insertBefore or cloneNode, etc.) from lightDOM to shadowDOM, you can do all styling you want.

      不使用<slot></slot>:slotted()

      (可能不称其为解决方法)这是一种不同的/强大的shadowDOM内容样式设置方式:

      (maybe not call it a workaround) It is a different/powerful way of styling shadowDOM content:

      Apple终于在2020年3月的Safari 13.1中实现了这一点

      Apple finally implemented this in Safari 13.1, March 2020

      请参阅:

      https://dev.to/webpadawan/css-shadow-parts-are-coming-mi5

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

      Note! ::part styles shadowDOM, <slot></slot> content remains in lightDOM!

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

      https://polymer-library.polymer-project.org/2.0/docs/devguide/style-shadow-dom#style-your-elements

      https://github.com/w3c/webcomponents/issues/331

      https://github.com/w3c/webcomponents/issues/745

      https://developer.mozilla. org/zh-CN/docs/Web/API/HTMLSlotElement/slotchange_event

      :: part()- https://developer.mozilla.org/zh-CN/docs/Web/CSS/::part

      ::part() - https://developer.mozilla.org/en-US/docs/Web/CSS/::part

      相关的答案: WCSLOT

      更改buttonclick上的广告位名称,并从lightDOM中提取新内容:

      Change the slot-name on buttonclick and pull in new content from lightDOM:

      <template id=MY-ELEMENT>
        <style>
          ::slotted([slot="Awesome"]){
            background:lightgreen
          }
        </style>
        <slot><!-- all unslotted content goes here --></slot>
        <slot id=answer name=unanswered></slot>
      </template>
      <style>
        img { /* style all IMGs in lightDOM */
          max-height: 200px;
          border:4px solid green;
        }
      </style>
      <my-element>
        SLOTs are: <button>Cool</button> <button>Awesome</button> <button>Great</button>
        <span slot=unanswered>?</span>
        <div  slot=Cool>   <img src="https://i.imgur.com/VUOujQT.jpg"></div>
        <span slot=Awesome><b>SUPER!</b></span>
        <div  slot=Awesome><img src="https://i.imgur.com/y95Jq5x.jpg"></div>
        <div  slot=Great>  <img src="https://i.imgur.com/gUFZNQH.jpg"></div>
      </my-element>
      <script>
        customElements.define('my-element', class extends HTMLElement {
          connectedCallback() {
            this.attachShadow({mode:'open'})
                .append(document.getElementById(this.nodeName).content.cloneNode(true));
            this.onclick = (evt) => {
                 const label = evt.composedPath()[0].innerText; // Cool,Awesome,Great
                 this.shadowRoot.getElementById("answer").name = label;
            }
          }
        });
      </script>

      这篇关于:: slotted CSS选择器,用于shadowDOM插槽中的嵌套子级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆