I'm experimenting with native web components, and so far I actually really like them.
I have created a microsite that has a homepage, about page, and a contact page, and a menu that works by changing the hash component of the URL.
However, I'm noticing an undesirable effect - whenever I switch from one "page" to another (which in reality, is just unmounting one native web component, and mounting another), for about half a second, I see the web component render with default styles, before painting with the styles that I've included within the shadow DOM.
Initially, my component was like this:
const template = document.createElement('template');
template.innerHTML = `
<style>
@import '../reset.css';
@import '../vars.css';
@import '../bodyText.css';
</style>
<div class="body-text">
<h1>Home page</h1>
<p>Home. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p>
`;
class HomePage extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.append(template.content.cloneNode(true));
}
}
export default HomePage;
I've tried to remedy the problem by removing the CSS import, and importing styles like this instead:
function createStylesheet(path) {
const linkElem = document.createElement('link');
linkElem.setAttribute('rel', 'stylesheet');
linkElem.setAttribute('href', path);
return linkElem;
}
const s1 = createStylesheet('../reset.css');
const s2 = createStylesheet('../vars.css');
const s3 = createStylesheet('../bodyText.css');
const template = document.createElement('template');
template.innerHTML = `
<div class="body-text">
<h1>Home page</h1>
<p>Home. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p>
`;
class HomePage extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.append(template.content.cloneNode(true));
this.shadowRoot.append(s1);
this.shadowRoot.append(s2);
this.shadowRoot.append(s3);
}
}
export default HomePage;
But still, there is a flash of unstyled content whenever the component is mounted.
This wouldn't be so much of a problem if it only happened when a component of a certain type first loaded, but the artefact is visible every time a custom component is mounted.
Is there any way to stop this from happening? I'd even happily forego the shadow DOM and just use BEM if it meant I could use nice, lightweight native web components!
I've heard its possible to prevent it from happening by using inline styles, but I'd prefer not to go down that route...I'd prefer to keep the CSS in a well-organised set of subdirectories.