::slotted CSS 用于 shadowDOM 槽中嵌套子项的选择器
::slotted CSS selector for nested children in shadowDOM slot
CSS ::slotted
select 或 select 元素的 <slot>
子元素。
但是,当尝试 select 孙子喜欢 ::slotted(*)
、::slotted(*) *
或 ::slotted(* *)
时,selector 似乎没有效果。
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>
请注意 span 如何没有边界。
这是预期的行为吗?我找不到具体的文档。
如果是,有没有办法解决这个问题?
样式化::阴影中的开槽元素DOM
TL;DR
-
在light中remains DOM,被反射到shadow[=296中的<slot>
=] DOM
::slotted(x)
瞄准光 DOM 外部元素(又名 'skin'),NOT 阴影中的 SLOT DOM
::slotted(x)
占用 basic selectors
可继承的样式逐渐进入阴影DOM
https://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 是 moved to shadowDOM
slotted lightDOM is NOT moved, it remains.. hidden.. in lightDOM
the content (IF slotted) is reflected to a <slot></slot>
或来自Google Developer Documentation
, .
' ; .
我使用术语 reflected 而不是 render 因为 render 意味着你可以访问它在阴影DOM.
你不能,因为开槽内容不在影子DOM...只反映 来自光DOM.
为什么 :slotted 的功能有限
尝试了更高级的阴影DOM样式。
WebComponents 版本 0 (v0) 有 <content>
和 ::content
;但它已从规范中删除:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/content
W3C 标准讨论的主要收获
(@hayatoito (Google 团队) here and here) 是:
所以在 V1 中我们有 :slotted
: https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted
补充 #1:复杂选择器允许 ::slotted 时的性能
来自 Mozilla 开发人员 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.
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 的简单选择器。 --> 基本上任何带有 space 的东西都不起作用
► 它只针对光DOM '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])
确认特异性规则,
但是(很简单)不会将重量添加到光DOM 皮肤选择器,所以永远不会获得更高的特异性。
在某些(罕见的)用例中,您可能需要!important
。
<style>
::slotted(H1) {
color: blue !important;
}
<style>
样式化开槽内容
另见:
#1 - 风格灯DOM
<span>
隐藏在光DOM中,在那里所做的任何更改将继续反射到它的槽[=296] =]表示法。
这意味着您可以在主 DOM
中使用 和 CSS 应用任何样式
(或者父影子DOM 容器,如果你将 <my-element>
包裹在一个容器中)
<style>
my-element span {
.. any CSS you want
}
<style>
#2 -(解决方法)将光DOM移动到阴影DOM
如果你移动光DOM到阴影DOM:this.shadowRoot.append(...this.childNodes)
您可以在阴影中进行所有样式设置DOM <style>
标签。
注意:您现在可以不再使用<slot></slot>
和:slotted()
。
<slot>s
仅适用于 反射 的内容DOM。
例如,一个元素将 自身 包裹在额外的阴影 DOM 层中,
所以没有CSS流血了,可以用<slot>s
,见:
#3 - ::部分(阴影部分)
这是一种 different/powerful 样式阴影的方式DOM 内容:
Apple 终于在 2020 年 3 月的 Safari 13.1 中实现了 shadowParts
见:
注意! ::part
样式 阴影DOM,
<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://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/slotchange_event
::part() - https://developer.mozilla.org/en-US/docs/Web/CSS/::part
示例:使用插槽作为路由器
更改按钮点击时的插槽名称并反射来自灯光的内容DOM:
<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>
CSS ::slotted
select 或 select 元素的 <slot>
子元素。
但是,当尝试 select 孙子喜欢 ::slotted(*)
、::slotted(*) *
或 ::slotted(* *)
时,selector 似乎没有效果。
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>
请注意 span 如何没有边界。
这是预期的行为吗?我找不到具体的文档。
如果是,有没有办法解决这个问题?
样式化::阴影中的开槽元素DOM
TL;DR
在light中remains DOM,被反射到shadow[=296中的
<slot>
=] DOM::slotted(x)
瞄准光 DOM 外部元素(又名 'skin'),NOT 阴影中的 SLOT DOM::slotted(x)
占用 basic selectors可继承的样式逐渐进入阴影DOM
https://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
- https://github.com/whatwg/html/issues/6051#issuecomment-816971072
背景
是的,::slotted()
不设置嵌套元素的样式是预期的行为。
slotted
这个词违反直觉,
这意味着元素 lightDOM 是 moved to shadowDOM
slotted lightDOM is NOT moved, it remains.. hidden.. in lightDOM
the content (IF slotted) is reflected to a<slot></slot>
或来自Google Developer Documentation
, .
' ; .
我使用术语 reflected 而不是 render 因为 render 意味着你可以访问它在阴影DOM.
你不能,因为开槽内容不在影子DOM...只反映 来自光DOM.
为什么 :slotted 的功能有限
尝试了更高级的阴影DOM样式。
WebComponents 版本 0 (v0) 有 <content>
和 ::content
;但它已从规范中删除:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/content
W3C 标准讨论的主要收获
(@hayatoito (Google 团队) here and here) 是:
所以在 V1 中我们有 :slotted
: https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted
补充 #1:复杂选择器允许 ::slotted 时的性能
来自 Mozilla 开发人员 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.
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 的简单选择器。 --> 基本上任何带有 space 的东西都不起作用
► 它只针对光DOM '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])
确认特异性规则,
但是(很简单)不会将重量添加到光DOM 皮肤选择器,所以永远不会获得更高的特异性。
在某些(罕见的)用例中,您可能需要!important
。
<style>
::slotted(H1) {
color: blue !important;
}
<style>
样式化开槽内容
另见:
#1 - 风格灯DOM
<span>
隐藏在光DOM中,在那里所做的任何更改将继续反射到它的槽[=296] =]表示法。
这意味着您可以在主 DOM
中使用 和 CSS 应用任何样式
(或者父影子DOM 容器,如果你将 <my-element>
包裹在一个容器中)
<style>
my-element span {
.. any CSS you want
}
<style>
#2 -(解决方法)将光DOM移动到阴影DOM
如果你移动光DOM到阴影DOM:this.shadowRoot.append(...this.childNodes)
您可以在阴影中进行所有样式设置DOM <style>
标签。
注意:您现在可以不再使用<slot></slot>
和:slotted()
。
<slot>s
仅适用于 反射 的内容DOM。
例如,一个元素将 自身 包裹在额外的阴影 DOM 层中,
所以没有CSS流血了,可以用<slot>s
,见:
#3 - ::部分(阴影部分)
这是一种 different/powerful 样式阴影的方式DOM 内容:
Apple 终于在 2020 年 3 月的 Safari 13.1 中实现了 shadowParts
见:
注意! ::part
样式 阴影DOM,
<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://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/slotchange_event
::part() - https://developer.mozilla.org/en-US/docs/Web/CSS/::part
示例:使用插槽作为路由器
更改按钮点击时的插槽名称并反射来自灯光的内容DOM:
<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>