从外部设置 Shadow DOM 样式

问题描述 投票:0回答:5

我正在寻找一种从外部设置 Shadow DOM 样式的方法。例如,我想将所有“span.special”元素中的所有文本的颜色设置为红色。包括来自 Shadow DOM 的“span.special”元素。我怎样才能做到这一点?

以前有 ::shadow 伪元素和 /deep/ 组合器又名 >>> 用于此目的。所以我可以写一些类似的东西

span.special, *::shadow span.special {
    color: red
}

但现在 ::shadow/deep/>>> 已被弃用。那么,我们有什么可以替代它们呢?

javascript css html styling shadow-dom
5个回答
15
投票

我确实尝试了很多方法,包括这里描述的方法。由于我使用外部 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");
  });

12
投票

仍然没有简单的方法来刺穿影子根,但这里有 3 种方法可以帮助你。请记住,您需要在 Web 组件内进行更改。

  1. 使用变量 v1 - 您需要传递属性并使用 Web 组件内的变量。

  2. 使用变量 v2 - 您将需要在 Web 组件内使用该变量。

  3. 使用

    ::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>


9
投票

您可以使用@import css,如另一个问题的answer中所述。

将规则包含在 shadow 树中的 style 元素内。

 <style>
   @import url( '/css/external-styles.css' )
 </style>

请注意,>>>组合器仍然是CSS范围模块草案的一部分。


7
投票

好吧,如果您正在使用无法更改的库 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 那样强大的外部造型方式。


0
投票

我使用了以下解决方案,因为它甚至可以与库组件一起使用,并且比通过 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);

注意:我还没有使用封闭的影子根来测试它。我想这不会起作用。

© www.soinside.com 2019 - 2024. All rights reserved.