Correct Way to Apply Global Styles into Shadow Dom

Correct way to apply global styles into Shadow DOM

There's no real drawback with solution 3:

  1. Whether you apply a CSS style to n elements in a main document, or to 1 element in n Shadow DOM, the style will be duplicated to the whole n elements anyways.

  2. If you import a document n times in n Shadow DOM, il will be actually be loaded only one time and reused through the browser cache.

After that, it will depend on the browser implementation of Shadow DOM and CSS styles, and you should see a performance degradation only the thousands of Shadow DOM.


2019 update for Chrome 73+ and Opera 60+

Now you can directly instanciate a CSSStyleSheet object and assign it to different Shadow DOMs.

This way the HTML won't be duplicated.

var css = new CSSStyleSheet()
css.replaceSync( "@import url( main.css )" )
host.shadowRoot.adoptedStyleSheets = [css]
host2.shadowRoot.adoptedStyleSheets = [css]

You can also apply it to the global document:

document.adoptedStyleSheets = [css]

The other advantage is that an update on the stylesheet will be applied to all Shadow DOMs (and document) that adopted it.

 css.replaceSync( '.color { color: red }' )

Global CSS effect on Shadow element. Why?

It's the normal behavior of CSS styles. The elements inserted in the Shadow DOM with <content> (in your example: <span class=name>...</span>) are actually part of the normal DOM, and therefore are affected by the global CSS styles.

If you don't dont want it, you should try another technique, like copying the light DOM elements into the Shadow DOM instead of using <content>.

Also, you should use Custom Elements v1 (and customElements.define()) and Shadow DOM v1 (and <slot>) instead of Custom Elements v0 (registerElement()) and Shadow DOM v0 (<content>) which are deprecated.

With Shadow DOM v1, you can use ::slotted() inside the Shadow DOM to select and style insterted elements.

You can then overload the CSS rule in the Shadow DOM <style> with the !important modifier:

line 21:

<style>
::slotted( span ) {
text-decoration: underline!important
}
</style>

Below is the complete snippet:

//CREATE CUSTOM ELEMENTclass MyContact extends HTMLElement {  constructor() {     super()    //retrieve template    var tpl = document.querySelector('#contact-form-tpl');    var tpl_ct = document.importNode(tpl.content, true);
//this <=> my-contact element -> create shadow var shadowRoot = this.attachShadow( {mode:'open'}) //createShadowRoot();
//show template in shadow DOM shadowRoot.appendChild(tpl_ct); }}
//REGISTER CUSTOM ELEMENTcustomElements.define("my-contact", MyContact);
span {  text-decoration: line-through}
<script src="https://cdnjs.cloudflare.com/ajax/libs/document-register-element/1.11.0/document-register-element.js"></script><span>HELLO</span><!--line through by css at LINE 6: OK--><my-contact>  <h1 slot=header>Contact X</h1>  <span slot=name>this is my name</span>  <span slot=phone>this is my phone</span></my-contact>

<template id="contact-form-tpl"> <style> span ::slotted( span ), span { text-decoration:underline!important } </style> <fieldset> <legend> <slot name=header></slot> <div> Name: <span><slot name="name"></slot></span> </div> <div> Phone: <slot name="phone"><span></span></slot> </div> <span>TEST</span><!-- only apply css at line 21: OK--> </legend> </fieldset></template>


Related Topics



Leave a reply



Submit