I am using Firefox 141.0.3.
I know there are several ways to have individual CSS properties pierce the Shadow DOM:
part
and myWebComponent:part()
In this case I actually want to import an entire stylesheet (and I don't want to write the stylesheet out inline in my .js
file).
First, I tried:
import myStyles from '/styles/my-styles.css' with {type: 'css'}
Firefox tells me it doesn't (currently) support assertions:
Uncaught SyntaxError: import assertions are not currently supported
Then, I tried:
import myStyles from '/styles/my-styles.css'
Firefox tells me it doesn't allow the MIME type:
Loading module from “/styles/my-styles.css” was blocked because of a disallowed MIME type (“text/css”)
Then I tried:
const myStyles = new CSSStyleSheet();
myStyles.replace(`@import url('/styles/my-styles.css')`);
Firefox tells me:
@import rules are not yet valid in constructed stylesheets.
What is (currently) the best way to go about importing an external stylesheet into a WebComponent with Shadow DOM in Firefox?
I came away from this issue for a few days and I've only come back to it this morning.
I needed a better solution, since with the polyfill solution I first implemented below, there were three instances of the WebComponent, which led to the browser fetching the CSS file from the server three times when I hard-refreshed the web page.
But, some time after that, there were twenty-three instances of the WebComponent, which led to the browser fetching the CSS file from the server twenty-three times.
This added 1.5 seconds or more to the initial download time.
I revised my approach and I have gone with the accepted solution below.
N.B. This approach will no longer be necessary once Firefox and Safari support CSS Module Script Imports:
import myStyles from '/styles/my-styles.css' with {type: 'css'}
See current progress, here:
A different approach:
<head>
of the document, normally: <link rel="stylesheet" href="/styles/my-styles.css" />
const stylesheet = [...document.styleSheets].find((styleSheet) => styleSheet.href.split('/').pop() === 'my-styles.css');
const stylesheetRules = [...stylesheet.cssRules];
const stylesheetText = stylesheetRules.reduce((accumulator, rule) => accumulator + rule.cssText, '');
I'd hoped this might be enough, but Firefox errored with:
Adopted style sheet must be created through the Constructable StyleSheets API
So...
StyleSheet
and populate it:const myStyles = new CSSStyleSheet();
myStyles.replace(stylesheetText);
WebComponent
adopt the constructed StyleSheet
in the (no longer asynchronous) connectedCallback()
:const myShadow = this.attachShadow({mode: 'open'});
myShadow.adoptedStyleSheets = [myStyles];
<link rel="stylesheet" href="/styles/my-styles.css" />
//**************************************************//
const stylesheet = [...document.styleSheets].find((styleSheet) => styleSheet.href.split('/').pop() === 'my-styles.css');
const stylesheetRules = [...stylesheet.cssRules];
const stylesheetText = stylesheetRules.reduce((accumulator, rule) => accumulator + rule.cssText, '');
const myStyles = new CSSStyleSheet();
myStyles.replace(stylesheetText);
class myWebComponent extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
const myShadow = this.attachShadow({mode: 'open'});
myShadow.adoptedStyleSheets = [myStyles];
[...]
}
}
This approach leads to the stylesheet being loaded once only when the page is hard-refreshed and cached for every soft-reload after that.