簡體   English   中英

::slotted CSS 選擇器,用於 shadowDOM 插槽中的嵌套子項

[英]::slotted CSS selector for nested children in shadowDOM slot

CSS ::slotted選擇器選擇<slot>元素的子元素。

但是,當嘗試 select 孫子時,例如::slotted(*)::slotted(*) *::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);
 <my-element> <p> <span>Test</span> </p> </my-element>

請注意跨度如何沒有邊框。

這是預期的行為嗎? 我無法為此找到具體的文檔。

如果是,有沒有辦法解決這個問題?

shadowDOM 中的樣式::開槽元素

TL;博士


背景

是的, ::slotted()不設置嵌套元素的樣式是預期的行為。

slotted這個詞是違反直覺的,
它意味着元素 lightDOM 被移動到 shadowDOM

開槽的 lightDOM沒有移動,它仍然是..隱藏的..在 lightDOM 中
內容(IF slotted)反映<slot></slot>

或者來自谷歌開發者文檔

,.
';.

我使用術語反射而不是渲染,因為渲染意味着您可以shadowDOM 中訪問它。
您不能,因為開槽的內容不在shadowDOM 中……僅從 lightDOM 中反射


為什么:slotted 功能有限

嘗試了更高級的 shadowDOM 樣式。

WebComponents 版本 0 (v0) 有<content>::content 但它已從規范中刪除:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/content

W3C 標准討論的主要內容
(@hayatoito(谷歌團隊)在這里這里)是:

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


補充 #1:性能 if::slotted 允許復雜的選擇器

來自 Mozilla 開發人員 Emilio:

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

性能問題是它增加了每個節點需要 go 查找影響它們的規則的子樹的數量。

現在的邏輯是這樣的:如果你有槽,遍歷你的槽並根據需要在它們的影子樹中收集規則。 這是代碼這很好,因為元素樣式的復雜性直接取決於您正在構建的陰影樹的復雜性,並且它只影響開槽節點。

如果您想允許組合子通過時隙,那么每個節點都需要查看其祖先和上一個兄弟鏈並查看其中哪些是時隙的,然后對它們的所有插槽執行該過程。 然后,最重要的是,您還需要更改通用選擇器匹配代碼,以便如果您不在正確的影子樹中,則不包含帶槽選擇器的選擇器不會匹配。

這是您為所有元素支付的成本,無論您使用的是 Shadow DOM 還是::slotted,而且可能只是行不通。


所以由於性能問題

:slotted( S )得到了有限的 CSS 選擇器功能:

  • ► 它只需要簡單的 S 選擇器。 --> 基本上任何有空格的東西都行不通

  • ► 它只針對 lightDOM的“皮膚” --> 也就是說,只有第一級

<my-element>
  <h1>Hello World</h1> 
  <p class=foo>
    <span>....</span>
  </p>
  <p class=bar>
    <span>....</span>
  </p>
</my-element>
  • ::slotted(h1)::slotted(p)有效

  • ::slotted(.foo)有效

  • ::slotted(span) (或任何更深的東西)將不起作用(不是“皮膚”元素)

注意: ::slotted([Simple Selector])確認符合特異性規則,
但是(很簡單)不會增加lightDOM皮膚選擇器的權重,因此永遠不會獲得更高的特異性。
在某些(罕見的)用例中,您可能需要!important

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

樣式化開槽內容

另請參閱: 將更多深度選擇應用於:主機 CSS 偽 class

#1 - 風格 lightDOM

<span>隱藏在 lightDOM 中,在那里所做的任何更改都將繼續反映到它的開槽表示。

這意味着您可以在主 DOM 中使用 CSS應用您想要的任何樣式
(如果您將<my-element>包裝在一個中,則為父 shadowDOM 容器)

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

#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 終於在 Safari 13.1 中實現了 shadowParts,2020 年 3 月

看:

筆記! ::part styles shadowDOM ,
<slot></slot>內容仍保留在lightDOM中!


參考

請注意:可能包含 v0 文檔!


示例:將插槽用作路由器

更改 buttonclick 上的 slot-name 並反映來自 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>/* style all IMGs in lightDOM */ img { max-height; 165px:border:3px dashed green } img:hover{ border-color:red } </style> <my-element><:-- content below is? lightDOM: --> 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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM