::slotted CSS 选择器用于 shadowDOM 插槽中的嵌套子级
Posted
技术标签:
【中文标题】::slotted CSS 选择器用于 shadowDOM 插槽中的嵌套子级【英文标题】:::slotted CSS selector for nested children in shadowDOM slot 【发布时间】:2020-08-20 21:38:42 【问题描述】:CSS ::slotted
选择器选择 <slot>
元素的子元素。
但是,当尝试使用 ::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>
注意跨度如何没有边框。
这是预期的行为吗?我找不到具体的文档。
如果是,有没有办法解决这个问题?
【问题讨论】:
【参考方案1】:在 shadowDOM 中设置 ::slotted 元素的样式
TL;DR
::slotted 规格:https://drafts.csswg.org/css-scoping/#slotted-pseudo
插入的内容保留在light DOM中,反映到@ shadow DOM
中的 987654348@::slotted(x)
以 lightDOM 外部元素(又名“皮肤”)为目标,不是 shadowDOM 中的 SLOT
::slotted(x)
接受basic selectors
可继承的样式渗入 shadowDOMhttps://lamplightdev.com/blog/2019/03/26/why-is-my-web-component-inheriting-styles/
有关 SLOT 和相关主题的最新 WHATWG 讨论,请参阅
https://github.com/whatwg/html/issues/6051#issuecomment-816971072 参与者:rniwa(Apple)、annvk(Mozilla)、dominic(Google) https://github.com/WICG/webcomponents/issues/934#issuecomment-906063140背景
是的,::slotted()
不设置嵌套元素的样式是预期行为。
slotted
这个词是违反直觉的,
这意味着元素 lightDOM 被 移动 到 shadowDOM
开槽的 lightDOM 没有移动,它仍然是..隐藏的..在 lightDOM 内容(IF 时隙)反映到
<slot></slot>
或来自Google Developer Documentation
????????????,???????????????????????????。 ????? ???'? ?????????? ???? ???;
我使用术语 reflected 而不是 render,因为 render 意味着您可以在 in shadowDOM 中访问它。您不能,因为槽位内容不在 shadowDOM 中...仅从 lightDOM 中反映。
为什么 :slotted 功能有限
尝试了更高级的 shadowDOM 样式。
WebComponents 版本 0 (v0) 有 <content>
和 ::content
;但它已从规范中删除:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/content
W3C 标准讨论的主要内容 (@hayatoito(Google 团队)here 和 here)是:
所以在 V1 中我们有 :slotted
: https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted
补充 #1:如果 ::slotted 允许复杂选择器的性能
来自 Mozilla 开发者 Emilio:
来源:https://github.com/w3c/webcomponents/issues/889
性能问题是它增加了子树的数量 每个节点都需要去寻找影响它们的规则。
现在的逻辑是这样的:如果你有槽,遍历你的槽 并根据需要在他们的影子树中收集规则。 This is the code 这很好,因为元素样式的复杂性 直接取决于您所使用的阴影树的复杂性 构建,它只影响开槽节点。
如果你想允许组合子通过时隙,那么每个节点都会 需要查看它的祖先和前兄弟链并查看哪个 其中一些被开槽,然后对所有槽执行该过程。 然后,最重要的是,您还需要更改通用选择器匹配 代码使不包含开槽选择器的选择器不 如果您不在正确的阴影树中,则匹配。
这是您为所有元素支付的成本,无论您是否 使用 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>
::slotted(h1)
和 ::slotted(p)
有效
::slotted(.foo)
有效
::slotted(span)
(或任何更深的东西)将不起作用(不是 'skin' 元素)
注意: ::slotted([Simple Selector])
确认符合特异性规则,
但是(很简单)不会向 lightDOM skin 选择器添加权重,因此永远不会获得更高的特异性。
在某些(罕见的)用例中,您可能需要!important
。
<style>
::slotted(H1)
color: blue !important;
<style>
样式化插槽内容
另见:Applying more in depth selection to the :host CSS pseudo class
#1 - 样式 lightDOM
<span>
隐藏在 lightDOM 中,在那里所做的任何更改都将继续反映到它的 slotted 表示。
这意味着您可以在主 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 层中,
所以 no CSS 会溢出,可以使用 <slot>s
,请参阅:
#3 - ::part(阴影部分)
这是一种不同的/强大的方式来设置 shadowDOM 内容的样式:
Apple 终于在 2020 年 3 月的 Safari 13.1 中实现了 shadowParts
见:
https://meowni.ca/posts/part-theme-explainer/
https://css-tricks.com/styling-in-the-shadow-dom-with-css-shadow-parts/
https://dev.to/webpadawan/css-shadow-parts-are-coming-mi5
https://caniuse.com/mdn-html_global_attributes_exportparts
注意! ::part
样式 shadowDOM,<slot></slot>
内容仍保留在 lightDOM 中!
参考
注意:可能包含 v0 文档!
https://css-tricks.com/encapsulating-style-and-structure-with-shadow-dom/
https://developers.google.com/web/fundamentals/web-components/shadowdom?hl=en#composition_slot
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/en-US/docs/Web/API/HTMLSlotElement/slotchange_event
::part() - https://developer.mozilla.org/en-US/docs/Web/CSS/::part
示例:将插槽用作路由器
在 buttonclick 上更改 slot-name 和 reflect 来自 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>
【讨论】:
关于性能评论,没有提供任何证据。我们需要看到数字。网络中有很多“慢”的 API,如果使用得当,它们也不是坏事。 @trusktr 是的……性能不佳是删除功能的可怕理由。例如:动画宽度的表现非常糟糕,但是否由开发人员决定。 @FeldsLiscia 如此真实。在大多数情况下,即使在最慢的低端手机上,甚至在智能手表上,这样的动画也能正常工作。动画一两件东西不同于动画 100 或 1000 件东西。开发人员应该有选项,并且知道何时使用它们。文档在这里很重要。以上是关于::slotted CSS 选择器用于 shadowDOM 插槽中的嵌套子级的主要内容,如果未能解决你的问题,请参考以下文章