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
Override styles in a shadow-root element
提问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.

