覆盖shadow-root元素中的样式

问题描述 投票:10回答:3

有没有办法改变阴影元素中的样式?具体来说,扩展/覆盖在css类中找到的一些属性?我正在使用名为Beanote的chrome扩展程序,自2017年4月(2017年)以来尚未更新,我想修复一个讨厌的错误。我发现一行css补丁对我来说足够了,但是我不知道如何应用它而不进入阴影元素本身并直接在开发工具中编辑这些样式。

我正在寻找一种方法:

/*global css rule*/
.the-class-name { property-name: my-value; }

覆盖这个:

/* style tag inside the shadow-root */
.the-class-name { property-name: bad-value; }

我在网上找到的涉及shadow-root override styleedit shadow-root styling的查询的大部分资源都与:host有关,如果它的意思是,它不适用于我的需要或::shadow不推荐使用的功能。

css web-component shadow-dom
3个回答
14
投票

由于样式的隔离(Shadow DOM的一个功能),您无法定义将在Shadow DOM范围中应用的全局CSS规则。

它可以使用CSS变量,但它们应该在阴影组件中显式实现(与第三方库不同)。

解决方法是直接在shadow DOM中注入样式行。

//host is the element that holds the shadow root:
var style = document.createElement( 'style' )
style.innerHTML = '.the-class-name { property-name: my-value; }'
host.shadowRoot.appendChild( style )

注意:只有在Shadow DOM mode设置为'open'时它才会起作用。


2019年Chrome 73+和Opera 60+的更新

现在可以直接实例化CSSStyleSheet对象并将其影响到Shadow DOM或文档:

var sheet = new CSSStyleSheet
sheet.replaceSync( `.color { color: pink }`)
host.shadowRoot.adoptedStyleSheets = [ sheet ] 

4
投票

Ionic V4选择向下图标颜色更改示例

document.querySelector('#my-select').shadowRoot.querySelector('.select-icon-inner').setAttribute('style', 'opacity:1');


ionViewDidEnter() {
    document.querySelector('#my-select').shadowRoot.querySelector('.select-icon-inner').setAttribute('style', 'opacity:1');
  }

如果要覆盖默认生成的shadowRoot样式,则必须在完全加载页面后调用js函数。


1
投票

扩展以前的答案。

外部样式总是胜过Shadow DOM中定义的样式,即当您添加引用正在样式化的组件的全局样式规则时。见:https://developers.google.com/web/fundamentals/web-components/shadowdom#stylefromoutside

否则,这将取决于元素shadow DOM是否嵌入了styleSheet,或者它是否采用了使用adoptedStyleSheets的样式表。

如果元素嵌入在元素中,则可以使用addRuleinsertRule向现有样式表添加或插入规则。这也适用于添加了adopedStyleSheets的样式表。

如前一个答案中所述,您可以将新样式表添加到采用的样式表列表中。当shadowRoot包含嵌入的styleSheet时,这也有效,因为adoptedStyleSheets优先,而styleSheetList是只读属性。

assert(myElement.shadowRoot.styleSheets.length != 0);
myElement.shadowRoot.styleSheets[0].addRule(':host', 'display: none;');

assert(myElement.shadowRoot.adoptedStyleSheets.length != 0);
`myElement.shadowRoot.adoptedStyleSheets[0].addRule(':host', 'display: none;');`

const sheet = new CSSStyleSheet();
sheet.replaceSync(`:host { display: none; }`);

const elemStyleSheets = myElement.shadowRoot.adoptedStyleSheets;

// Append your style to the existing style sheet.
myElement.shadowRoot.adoptedStyleSheets = [...elemStyleSheets, sheet];

// Or if just overwriting a style set in the embedded `styleSheet`
myElement.shadowRoot.adoptedStyleSheets = [sheet];

0
投票

我想在其中一条评论中回答@Renato给出的答案,因为它指出了解决从托管应用程序定制WebComponent问题的好的恕我直言。

@Supersharp是正确的,外部CSS规则没有传播到Shadow Root,这是设计的。

CSS变量是一个很好的方向,但从我个人的经验来看,单个用法的价值有点过分,是的,它们必须得到WebComponent的支持。

通过继承传播:host属性(正如@Renato提到的那样)是,恕我直言,与API设计一致的完美正确的模式:

  • 自定义元素(:host)的CSS规则是外部规则可以覆盖的设计
  • :host的子项,Shadow DOM的内部内容,可以默认或通过显式规则继承:host的CSS规则 - 这也是设计

我会说,在适用的情况下,在考虑CSS样式表注入之前最好采用这种方法,并且也不会受到open模式的限制。

当然,这种方法在以下情况下无济于事:

  • 内部元素不继承:host的相关规则
  • Web组件的结构非常复杂,因此单个qazxsw poi根本无法帮助他们

然而,再次根据我自己的经验,具有理想的可覆盖CSS规则的简单组件可以从通过:host传播规则的非侵入模式中获益很多。

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