For the last two weeks, we've been looking at why styling elements in the shadow DOM sucks so bad, and what to do about it.
So far, we've looked at using inline styles, external stylesheets, CSS variables, and parts.
Today, let's look at the final approach we can use: constructable stylesheets.
Our example element
Just to recap, we have a <count-up>
element, like this…
Which, when the Web Component JavaScript loads, renders HTML like this…
<count-up> #shadow-root (closed) <button>Clicked 0 Times</button> </count-up>
And it's styled using inline CSS and CSS variables like this…
// Inject the HTML into the shadow DOM this.root.innerHTML = `<style> button { background-color: var(--bg-color, rebeccapurple); border: var(--border, 0); border-radius: var(--border-radius, 0.25em); color: var(--color, white); font-family: var(--font, 'PT Serif', sans-serif); font-size: var(--font-size, 1.2em); padding: var(--padding, 0.25em 0.5em); } </style> <button>Clicked ${this.count} Times</button>`;
This is particularly annoying if you've got a global stylesheet that already has styles defined for the elements in the shadow DOM.
The other week, we looked at linking to an external stylesheet, like this…
// Inject the HTML into the shadow DOM this.root.innerHTML = `<link rel="stylesheet" type="text/css" href="/path/to/buttons.css"> <button>Clicked ${this.count} Times</button>`;
This prevents you from having to duplicate your styles in multiple places.
But in some browsers, this approach may result in the same CSS file being downloaded multiple times.
Constructable stylesheets
Constructable Stylesheets are a way to reuse CSS across the Shadow DOM.
They provide a way to create a stylesheet with JavaScript. It gets loaded into the browser, and can be accessed across components in the Shadow DOM, without loading multiple times.
First, create a new stylesheet using the new CSSStyleSheet()
constructor. Then, use the CSSStyleSheet.replaceSync()
method to add your styles.
Both of these steps should take place outside of your web component class.
let stylesheet = new CSSStyleSheet(); stylesheet.replaceSync( `button { background-color: var(--bg-color, rebeccapurple); border: var(--border, 0); border-radius: var(--border-radius, 0.25em); color: var(--color, white); font-family: var(--font, 'PT Serif', sans-serif); font-size: var(--font-size, 1.2em); padding: var(--padding, 0.25em 0.5em); }` );
Inside the constructor()
, you can use the ShadowRoot.adoptedStylesheets
property to assign an array with your stylesheet
. This attaches it inside the Shadow DOM.
/** * The class constructor object */ constructor () { // Gives element access to the parent class properties super(); // Component properties this.count = 0; // Create a shadow root this.root = this.attachShadow({mode: 'closed'}); // Attach the style sheet to the Shadow DOM of this component this.root.adoptedStyleSheets = [stylesheet]; // Inject the HTML into the shadow DOM this.root.innerHTML = `<button>Clicked ${this.count} Times</button>`; // Listen for events // ... }
The stylesheet
gets loaded once, then "adopted" within each of your component Shadow DOMs.
Importing stylesheets
You can also load an existing stylesheet using ES module imports instead.
The with
operator with a type
property of css
is required, or the browser will throw an error because the expected MIME type will not match the file being imported.
import stylesheet from './buttons.css' with { type: 'css' };
Unfortunately, at this time with { type: 'css' }
only work in chromium browsers. Hopefully that will change in the near future.
Cheers,
Chris
Want to share this with others or read it later? View it in a browser.
0 Komentar untuk "[Go Make Things] Styling Web Component elements in the shadow DOM with constructable stylesheets"