我正在寻找一种从外部设置 Shadow DOM 样式的方法。例如,我想将所有“span.special”元素中的所有文本的颜色设置为红色。包括来自 Shadow DOM 的“span.special”元素。我怎样才能做到这一点?
以前有 ::shadow 伪元素和 /deep/ 组合器又名 >>> 用于此目的。所以我可以写一些类似的东西
span.special, *::shadow span.special {
color: red
}
但现在 ::shadow、/deep/ 和 >>> 已被弃用。那么,我们有什么可以替代它们呢?
我确实尝试了很多方法,包括这里描述的方法。由于我使用外部 Web 组件库,因此我无权修改这些组件。所以,唯一对我有用的解决方案是使用 JS
querySelector
,就像这样:
document.querySelector("the-element.with-shadow-dom")
.shadowRoot.querySelector(".some-selector").setAttribute("style", "color: black");
不是最好的解决方案,不适合大型样式,但确实适用于小的增强。
@John 这是使用 Chrome 83.0.4103.116 进行测试的(仍将在 Safari 中进行测试),我对 Ionic (v5)
ion-toast
组件进行了测试。这是我使用的(几乎)真实代码:
import { toastController } from '@ionic/core';
let toastOpts = {
message: "Some message goes here.",
cssClass: "toast-with-vertical-buttons",
buttons: [
{
text: "Button 1",
side: 'end'
},
{
text: "Button2",
side: 'end'
},
{
icon: "close",
side: "start"
}
]
}
toastController.create(toastOpts).then(async p => {
let toast = await p.present(); // this renders ion-toast component and returns HTMLIonToastElement
toast.shadowRoot.querySelector('div.toast-button-group-end').setAttribute("style", "flex-direction: column");
});
仍然没有简单的方法来刺穿影子根,但这里有 3 种方法可以帮助你。请记住,您需要在 Web 组件内进行更改。
使用变量 v1 - 您需要传递属性并使用 Web 组件内的变量。
使用变量 v2 - 您将需要在 Web 组件内使用该变量。
使用
::part()
- 您需要向要在 Web 组件中设置样式的元素添加部件属性。 (注意:这个伪元素得到了很好的支持,但仍处于实验模式,因此在生产中使用它之前请确保您了解这一点)。
运行下面的代码示例以了解详细信息。
const elA = document.querySelector('custom-container-a');
const shadowRootA = elA.attachShadow({mode:'open'});
shadowRootA.innerHTML = '<style>:host([border]) {display:block;border: var(--custom-border);}</style>'+
'<p>Shadow content A</p>'
const elB = document.querySelector('custom-container-b');
const shadowRootB = elB.attachShadow({mode:'open'});
shadowRootB.innerHTML = '<style>p {display:block;color: var(--custom-color, blue);}</style>'+
'<p>Shadow content B</p>'
const elC = document.querySelector('custom-container-c');
const shadowRootC = elC.attachShadow({mode:'open'});
shadowRootC.innerHTML = '<p part="paragraph">Shadow content C</p>'
/* Normal way of styling */
p {
color: orange;
}
/* Using variables version 1 */
custom-container-a {
--custom-border: 3px solid gold;
}
/* Using variables version 2 */
custom-container-b {
--custom-color: green;
}
/* Using ::part() */
custom-container-c::part(paragraph) {
color: magenta;
}
<p>Light content</p>
<custom-container-a border></custom-container-a>
<custom-container-b></custom-container-b>
<custom-container-c></custom-container-c>
好吧,如果您正在使用无法更改的库 Web 组件,@import 不是一个解决方案...
最后我找到了几种方法:
1)级联。 Shadow DOM 的宿主元素的样式也会影响 Shadow DOM 元素。如果您需要为 Shadow DOM 的特定元素(而不是每个元素)设置样式,则不是一个选项。
2)自定义属性https://www.polymer-project.org/1.0/docs/devguide/styling 如果 Web 组件的作者提供了这样的信息。
3)在 Polymer 中,也有自定义 Mixin https://www.polymer-project.org/1.0/docs/devguide/styling
4)@import,但仅适用于非库组件
所以,有几种可能性,但它们都是有限的。没有像 ::shadow 那样强大的外部造型方式。
我使用了以下解决方案,因为它甚至可以与库组件一起使用,并且比通过 JS 手动设置所有内容的样式更简单。
编写一个“customization.css”,其中包含要嵌入到影子根中的样式。
然后通过JS给shadow root添加一个
<link rel="stylesheet" href="customization.css">
:
let lnk = document.createElement("link");
lnk.rel = "stylesheet";
lnk.href = "link to your customization.css";
let customElement = document.querySelector("your-custom-element");
customElement.shadowRoot.insertBefore(lnk, customElement.shadowRoot.firstChild);
注意:我还没有使用封闭的影子根来测试它。我想这不会起作用。