javascript Override styles in a shadow-root element

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47625017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:30:54  来源:igfitidea点击:

Override styles in a shadow-root element

javascriptcssweb-componentshadow-dom

提问by Andrew

Is there a way to change styles found in a shadow element? Specifically, extend/overwrite some properties found in a css class? I am using a chrome-extension called Beanotewhich hasn't been updated since April(2017) and there's a pesky bug I'd like to fix. I found that one line of css patches it up enough for me, but I am at a loss at applying it without going inside of the shadow element itself and directly editing those styles in the dev tools.

Is there a way to change styles found in a shadow element? Specifically, extend/overwrite some properties found in a css class? I am using a chrome-extension called Beanotewhich hasn't been updated since April(2017) and there's a pesky bug I'd like to fix. I found that one line of css patches it up enough for me, but I am at a loss at applying it without going inside of the shadow element itself and directly editing those styles in the dev tools.

I'm looking for a way for this:

I'm looking for a way for this:

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

to overwrite this:

to overwrite this:

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


Most of the resources I've found online with queries involving shadow-root override styleor edit shadow-root stylinghad something to do with :hostwhich, if its meant for this, doesn't work for my needs or deprecated functionality like ::shadow.


Most of the resources I've found online with queries involving shadow-root override styleor edit shadow-root stylinghad something to do with :hostwhich, if its meant for this, doesn't work for my needs or deprecated functionality like ::shadow.

回答by Supersharp

Because of the isolation of styles, which is a feature of Shadow DOM, you cannot define a global CSS rule that will be applied in the Shadow DOM scope.

Because of the isolation of styles, which is a feature of Shadow DOM, you cannot define a global CSS rule that will be applied in the Shadow DOM scope.

It could be possible with CSS variables but they should be implemented explicitly in the shadowed component (which is not the case with this 3rd party library).

It could be possible with CSS variables but they should be implemented explicitly in the shadowed component (which is not the case with this 3rd party library).

A workaround is to inject the line of style in the shadow DOM directly.

A workaround is to inject the line of style in the shadow DOM directly.

//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 )

NB: it will work only if the Shadow DOM modeis set to 'open'.

NB: it will work only if the Shadow DOM modeis set to 'open'.



2019 update for Chrome 73+ and Opera 60+

2019 update for Chrome 73+ and Opera 60+

Now it is possible to instantiate a CSSStyleSheet object directly and to affect it to a Shadow DOM or a document:

Now it is possible to instantiate a CSSStyleSheet object directly and to affect it to a Shadow DOM or a document:

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

回答by riguang zheng

Ionic V4 select down icon color change example

Ionic V4 select down icon color change example

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');
  }

If you want overwrite the default generated shadowRoot style then have to call js function after page loaded fully.

If you want overwrite the default generated shadowRoot style then have to call js function after page loaded fully.

回答by holmberd

Extending on the previous answers.

Extending on the previous answers.

Outside styles always win over styles defined in the Shadow DOM, i.e. when you add a global style rule that reference the component you are styling. See: https://developers.google.com/web/fundamentals/web-components/shadowdom#stylefromoutside

Outside styles always win over styles defined in the Shadow DOM, i.e. when you add a global style rule that reference the component you are styling. See: https://developers.google.com/web/fundamentals/web-components/shadowdom#stylefromoutside

Otherwise this will depend on if the elements shadow DOM was embedded with a styleSheet, or if it adopted a style-sheet using adoptedStyleSheets.

Otherwise this will depend on if the elements shadow DOM was embedded with a styleSheet, or if it adopted a style-sheet using adoptedStyleSheets.

If the element was embedded in the element you can add or insert a rule to the existing style-sheet using addRuleor insertRule. This also work for style-sheets added with adopedStyleSheets.

If the element was embedded in the element you can add or insert a rule to the existing style-sheet using addRuleor insertRule. This also work for style-sheets added with adopedStyleSheets.

As mentioned in the previous answer, you can append a new style-sheet to the list of adopted style-sheets instead. This also work when the shadowRoot contains a embedded styleSheet, since adoptedStyleSheetstakes precedence, and styleSheetListis a read-only property.

As mentioned in the previous answer, you can append a new style-sheet to the list of adopted style-sheets instead. This also work when the shadowRoot contains a embedded styleSheet, since adoptedStyleSheetstakes precedence, and styleSheetListis a read-only property.

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];

回答by GullerYA

I'd like to second an answer given by @Renato in one of the comments, since it points out the good, IMHO, way to solve the problem of customizing a WebComponent from the hosting application.

I'd like to second an answer given by @Renato in one of the comments, since it points out the good, IMHO, way to solve the problem of customizing a WebComponent from the hosting application.

@Supersharp is right in the fact, that the external CSS rules are notpropagating into thee Shadow Root, that's by design.

@Supersharp is right in the fact, that the external CSS rules are notpropagating into thee Shadow Root, that's by design.

CSS variables are a good direction, but from my personal experience are a bit of an overkill for a value of a singular usage, AND yes, they MUST be supported be the WebComponent up-front.

CSS variables are a good direction, but from my personal experience are a bit of an overkill for a value of a singular usage, AND yes, they MUST be supported be the WebComponent up-front.

Propagatingthe properties through the :hostvia inheritance(exactly as @Renato mentioned) is, IMHO, the perfectly right pattern aligned with the API design:

Propagatingthe properties through the :hostvia inheritance(exactly as @Renato mentioned) is, IMHO, the perfectly right pattern aligned with the API design:

  • Custom element's (:host's) CSS rules are by design overridable by the outer rules
  • :host's children, the inner content of the Shadow DOM, MAY inherit the CSS rules of the :host, either by default or by explicit rule - and this is too, by design
  • Custom element's (:host's) CSS rules are by design overridable by the outer rules
  • :host's children, the inner content of the Shadow DOM, MAY inherit the CSS rules of the :host, either by default or by explicit rule - and this is too, by design

I'd say, that where applicable, this approach would better be taken before considering CSS stylesheet injection, and also does not suffer from the limitation of openmode only.

I'd say, that where applicable, this approach would better be taken before considering CSS stylesheet injection, and also does not suffer from the limitation of openmode only.

Of course, this approach won't help when:

Of course, this approach won't help when:

  • Inner elements are not inheriting relevant rules from the :host
  • The structure of a WebComponent is quite complex, so that single :hostsimply can't help them all
  • Inner elements are not inheriting relevant rules from the :host
  • The structure of a WebComponent is quite complex, so that single :hostsimply can't help them all

Yet, again from my own experience, simple components with desirably overridable CSS rules may benefit much from the non-intrusive pattern of propagating rules via :host.

Yet, again from my own experience, simple components with desirably overridable CSS rules may benefit much from the non-intrusive pattern of propagating rules via :host.