Description
With Cascading Stylesheet Module scripts on the horizon we will soon have the ability to import CSSStyleSheets directly into JS, like so:
import sheet from './styles.css' assert {type: 'css'};
Problem
The semantics here are fine for unbundled apps, but bundling becomes tricky. If you have two .css files in an app, you can't just combine them. ie:
import sheet1 from './styles1.css' assert {type: 'css'};
import sheet2 from './styles2.css' assert {type: 'css'};
Is not compatible with:
import sheet from './styles1and2.css' assert {type: 'css'};
The current workaround is to compile CSS into JS modules, which defeats some of the performance benefit of having the browser directly load and parse CSS.
Web Bundles might solve this problem generically for multiple file types, though its future on multiple browsers seems unclear right now.
Proposal: @sheet
To fix this and allow bundling of CSS, could we introduce an at-rule that contains an entire style sheet as its contents?
For example, there could be a @sheet
rule which allows files to contain named stylesheets:
styles1and2.css:
@sheet sheet1 {
:host {
display: block;
background: red;
}
}
@sheet sheet2 {
p {
color: blue;
}
}
These could be imported separately from JS:
import {sheet1, sheet2} from './styles1and2.css' assert {type: 'css'};
And also be available on the main style sheet:
import styles, {sheet1, sheet2} from './styles1and2.css' assert {type: 'css'};
styles.sheet1 === sheet1;
styles.sheet2 === sheet2;
Relation to existing approaches
The proposal is most obviously relevant to code that manages CSSStyleSheets in JS - ie, users of Constructible StyleSheets and the API currently named adoptedStyleSheets.
It would also be useful as a bridge to userland CSS loaders that do bundling and scoping via selector rewriting. By standardizing bundling, scoping could be done with client-side utilities:
import {sheet1, sheet2} from './styles.css' assert {type: 'css' };
// doesn't yet exist, but a utility that re-writes class selectors and returns
// an object with a .sheet property and properties for each class
import {scopeSheet} from 'css-module-utilities';
const scopedSheet1 = scopeSheet(sheet1);
const scopedSheet2 = scopeSheet(sheet2);
document.adoptedStyleSheets.push(scopedSheet1.sheet, scopedSheet2.sheet);
document.append(`<div class="${scopedSheet1.fooClass}"></div>`);
document.append(`<div class="${scopedSheet2.barClass}"></div>`);