-
Notifications
You must be signed in to change notification settings - Fork 668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple stylesheets per file #5629
Comments
Early thoughts: I like this, though it might not replace CSS bundlers in some really performance-sensitive cases. There is still one fetch incurred for the But, it reduces the cost of using CSS modules in production to just 1 extra fetch, which is down from N extra fetches for N stylesheets. So for the cost of the one fetch, you cut out one part of the build/bundling process, get some perf benefit from parsing CSS directly without passing it through the JS parser, and the resulting production code will be easier to read and reason about than production code that had CSS bundled in the JS. [1] Last year I did some rough experiments to try to measure this potential perf benefit. I observed real differences in both time and memory, although you need a lot of iterations before it starts to be really observable: https://dandclark.github.io/json-css-module-notes/#css-module-performancememory-examples |
If there is a way to add this to the polyfill I would be more than happy to include this in the SystemJS module types polyfill as well. It seems a great feature. |
@justinfagnani A small typo correction for clarity: you've got |
Thanks @dandclark! Updated |
Dumb question from someone lacking context about CSS modules: these aren't compatible because sheet1 and sheet2 are both |
@gsnedders correct |
This sounds fairly reasonable to me. Semantically, this is basically a more convenient way to write |
cc @bmeck this seems like a good addition for the arbitrary module names, if my bundling still want to reference the names somehow. |
I like this as it also helps on a better usage of dynamic |
This proposal is very interesting to the Parcel team, and seems to mirror the Module Fragments proposal in the JavaScript world. Current approaches to bundling CSS by simply concatenating them are prone to ordering issues that can cause specificity problems. Sometimes bundling is simply not possible to do correctly due to this. An approach that allows natively combining separate sheets together that can be applied in the correct order would be very useful. 👍 |
cc'ing @littledan who is working on the related module declarations. If language-specific bundling is needed despite web bundles, maybe we need to push this forward for CSS. |
It turns out you can emulate this feature by abusing If there's an unknown supports function, the parsed stylesheet will still contain the rules inside @supports sheet(styles-one.css) {
//...
}
@supports sheet(styles-two.css) {
//...
} Then we can rewrite CSS module script imports from : import styles from './styles-one.css' assert {type: 'css'}; to: import $bundledStyles from './styles-bundle.css' assert {type: 'css'};
import {getBundledSheet} from 'lit/get-bundled-sheet.js';
const styles = getBundledSheet($bundledStyles, 'styles-one.css'); where Proof of concept here: https://lit.dev/playground/#gist=5fab7cc0987e6f1610ba3bd4f432f02c (requires import assertions support to work) @tabatkins adding native support for something like |
This seems like a good progression using assertions. Bundles would become much more useful from CSS perspective. /* bundle.css */
@layer defaults, common, brand, components;
@sheet designsystemstyles {
@layer commmon {
...
}
}
@sheet nameofbrand {
@layer brand {
...
}
} |
As I said in my previous comment, I think it's a very reasonable suggestion, I just haven't spent any time speccing it out. ^_^ A few questions that probably need resolving, tho:
|
1 and 4 in concert beg the question of what is returned at |
I presume the top-level sheet is the default export, and |
Shouldn’t user-defined sheet (and layer) names be either quoted strings or dash-idents? |
No, not necessarily. They're user-controlled, so there's no need for strings (they can comfortably remain in the identifier syntax). And these names won't mix with other CSS values, so there's no particular need to mark them out as user-defined; plus they're meant to map to JS identifiers, so dashed-idents would be inconvenient. |
If the goal is bundling files that otherwise would be part of the module graph, I think some of the questions you raised @tabatkins seem to me to have relative obvious answers, and I would agree with @Westbrook's responses. The main thing for me is that the module graph is keyed by URL, and so is flat in that sense, so |
That makes sense. 👍 |
Agenda+ to check the group's temperature on this idea (and figure out what spec it would go in). To sum up: The problem to solve is bundling stylesheets together. (Particularly for importing in a JS import, but also more generally to consolidate multiple requests into fewer, larger requests.) There are some inconvenient workarounds today (
So for example, given a stylesheet like: @sheet one { .bar {...} }
@sheet two { .baz {...} }
.foo {...} then JS can import the sheet like: import topLevel, {one, two} from "./combinedSheet.css"; Remaining design questions:
|
If there were an accompanying "apply this sheet here" @rule, it could effectively become a "mixin." @sheet redMixin {
:scope {
background: red;
}
} .myContainer {
@apply-sheet redMixin;
} |
For full mixin functionality, you would want the ability to pass in arguments. |
I believe that this feature also provides a way to handle a recent set of community requests that have surfaced around component customization. If Web Component library authors distribute their CSS in a single file with |
I’m wondering if |
@LeaVerou I would think that If a sheet should be explicitly exported, maybe the syntax should be @export @sheet sheet2 {
p {
color: blue;
}
} I'm not sure if @-rules can work that way though. |
@justinfagnani I’m not sure what a mechanism to export selectors or class names would look like. Rulesets, mixins, functions can already be exported with this rule since its contents would be |
This is a worthwhile line of investigation, and would likely benefit from actual user testing or surveying, etc. Historically, we've done With this in mind, I wonder if the use of |
Some ideas are in here, though without the
What if you wanted to import a single mixin and apply it in a specific place, not a whole stylesheet? |
Does this feature open up the path to real "CSS modules"? Right now, all CSS imports are side-effectful, but
Also it would be useful to be able to rename sheets when importing. I think this functionality is essential for any module-like system. @import "foo.css" sheets(A as X, B as Y);
@sheet X;
@sheet Y; Lastly — and this might be far-fetched — maybe there should be some reserved sheet names that have special meaning. For example, <head>
<style>
@sheet A {…}
@sheet B {…}
</style>
</head>
<div>
<template shadowrootmode="open">
<style type="module">
@sheet inherit.A;
@sheet inherit.B;
/* or just @sheet inherit; */
</style>
</template>
</div> Regardless of the specific ideas and syntaxes I illustrated, I think we should all be thinking about how to make CSS (and HTML) better and more useful on its own, even when JS is not involved. |
CSS imports only return a CSSStyleSheet object - they don't have any side-effects. |
I'm talking about CSS |
100% agree - I would naturally assume I could
This syntax is ugly imo. Particularly if you are using other |
In my previous comment, I described a CSS way to import an existing Another useful thing would be the ability to name a regular stylesheet from HTML, using an attribute like <link rel="stylesheet" href="legacy.css" name="legacy" /> This would give you a |
With Cascading Stylesheet Module scripts on the horizon we will soon have the ability to import CSSStyleSheets directly into JS, like so:
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:
Is not compatible with:
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:
These could be imported separately from JS:
And also be available on the main style sheet:
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:
The text was updated successfully, but these errors were encountered: