Skip to content

Multiple stylesheets per file #5629

Open
@justinfagnani

Description

@justinfagnani

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>`);

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions