-
Notifications
You must be signed in to change notification settings - Fork 688
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
Proposal: CSS @sheet #11509
Comments
FWIW, a fragment pointing into an HTML file seems like the wrong way to refer to You could consider extending the fragment syntax again to allow it to explicitly navigate into inline CSS, but I feel like a new attribute might be a better way to do this, as discussed in w3ctag/design-reviews#1000 (comment). |
Will there be a restriction on where |
Yes, there are restrictions on where This was discussed here: #5629 (comment) The discussion around |
Good proposal 👍
With that in mind I think that nesting should be allowed and that using These should all be equivalent: 1:
@sheet foo {
@sheet bar {}
} 2:
@sheet foo {
@import "bar.css";
} 3:
@import "foo.css";
@import "bar.css"; Is there a reason we can't do this? I agree that for the order
I know that current frameworks (vite? or vue?) already use this. Anonymous sheets should also be supported. @sheet {} Only having named sheets makes it impossible to use this when bundling, despite that being one of the stated goals in the explainer. All CSS authors should be able to benefit from this feature, not only those using shadow dom. Having @import "foo.css";
@import "https://some-framework.com/index.css";
@import "bar.css"; The only way to bundle that today is to rewrite as: @import url('data:text/css;base64,...');
@import "https://some-framework.com/index.css";
@import url('data:text/css;base64,...'); While with @sheet { /* contents of foo.css */ }
@import "https://some-framework.com/index.css";
@sheet { /* contents of bar.css */ } Relative urls have some sharp edges, especially when using in custom props. Maybe it makes sense to also have a This This would allow all relative urls to remain as they were written without any unexpected behavior differences between bundled or unbundled stylesheets. Before bundling:
:root {
background: url(../images/bar.jpg);
} When bundled the relative urls will break unless there is some provision:
@sheet {
@base url("https://www.example.com/public/styles/");
:root {
background: url(../images/bar.jpg);
}
} I think it would be ideal if Currently the landscape for CSS bundlers is pretty bleak. There aren't many tools that actually qualify as CSS bundlers and the most modern offerings don't even work right. Having |
The CSS Working Group just discussed
The full IRC log of that discussion<emilio> slides: https://docs.google.com/presentation/d/1zE9NgFltry9Qor6ajT695wZiN74zEpydtc1oEbzlhOw/edit#slide=id.p<emilio> kschmi: justin proposed this in 2020 <emilio> ... great discussion in 2023 where there was a resolution to add it to css-cascade <emilio> ... and we have some suggestions to expand it <emilio> ... so I want to touch on those <emilio> ... quick recap <astearns> new explainer: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/AtSheet/explainer.md <emilio> ... main initial goal is bundling <emilio> ... non-obvious is that this is not obvious but this helps compression rations <emilio> ... if you can combine more things into one file dictionaries you get more hit <emilio> ... some testing gives 0.4% compression improvements, so not massive but not nothing <emilio> ... the important thing I want to go through is that there's a solution for sharing inline styles with declarative shadow DOM <emilio> ... core concept was resolved in 2023 <emilio> ... where we allowed to reference fragments <emilio> ... not yet in the cascade spec <emilio> ... so that was the original proposal <emilio> ... so you have an `@sheet` block with an identifier and you can import them with a constructable stylesheet <emilio> ... so that's kinda the bundling scenario. The CSS bits are a pre-requisite <emilio> ... but we can't get the JS part until CSS adds the syntax <emilio> ... so `<link rel=foo.css#fragment>` and also `@import` <emilio> ... so it can cache the file and only make one request <emilio> q+ <emilio> ... hasn't been spec'd yet, but I think that's worth doing independently <emilio> ... but the extension is why doesn't this work for same-page URL <noamr> q+ <emilio> ... so plain fragments would work on inline styles <fantasai> scribe+ <bramus> scribe+ <astearns> ack emilio <fantasai> emilio: 2 things that come to mind <fantasai> emilio: 1. Why is this CSS-specific, in the sense that other resources ... including fragments and stuff <fantasai> emilio: This introduces quite a divergence in how we interpret URLs <fantasai> emilio: What you're proposing feels a bit weird because a plain fragment URL usually references the same document <fantasai> emilio: I guess we do have some precedent for some fragment-only URLs being a bit special <fantasai> emilio: One thing I'm concerned about, how does this behave-- if a browser doesn't implement it, the browser pulls the whole stylesheet and ignores it <matthieud> q+ <fantasai> emilio: it would import nested stylesheets <fantasai> emilio: feels like a more explicit mechanism here would be nice, but maybe we can live with this? <fantasai> emilio: I'm a bit worried about feature detection and fallbacks <fantasai> scribe- <astearns> q+ justin <astearns> ack noamr <miriam> We allow `supports()` in imports <bramus> noamr: When i see the # i expect it to be an id <bramus> … mixes html and css too much <bramus> … would prefer so,meting that has a sheet attr on link <bramus> … and other modifier to import, we have one for layer <bramus> … in general would be careful to use hasehs for sth that is not dom id <bramus> … confuses things <florian> q? <bramus> kurt: fragment already acceptd in prior discussion <bramus> … mgiht need to be revisited <bramus> … if fragment does work, much like acnhors you dont need a URL it means local <florian> q+ <bramus> … this is building on that <bramus> … there’s a precedent: if there is no file assume it is in the same doc <bramus> … only thing doing that is anchors, which is excepction to a lot of things <bramus> … if we do revisit fragment for this scenario, then we need to revisit for this <bramus> … other syntax or attr … would feel inconsistsent to not do this <bramus> noamr: wnated to say that it is different <bramus> … fragmetns and svg clip path and shapes – there are precedents but they refer to the dom id <bramus> … no prob with multidoc <astearns> ack dbaron <bramus> dbaron: from a URL design perspective the meaning of a fragment is generally specific to the mime-type of th resource <fantasai> +1 dbaron <bramus> … the idea that in a css file to refer to an @sheet can be sensible <justinf> +1 as well <bramus> … and in an HTML file they already refer to IDs and we should be very careful about changing that <bramus> … I could imagine with an @sheet inside a style element, and then use the id of the style element <justinf> fragments without a preceding URL refer to something in the HTML document already <bramus> … one of the design principles here is the meaning of fragment in a URL is specificy to the mime-type <emilio> q+ <bramus> kurt: makes sense <bramus> … we do have a .css file in this example <bramus> … but there is HTML and there is a mismatch witht he mimetype <ydaniv> q+ <bramus> … great point <noamr> +1, exactly, I have no problem with it inside CSS files <astearns> ack matthieud <bramus> matthieud: answer for emilio about old browser <bramus> … that dnt udnerstand @sheet <castastrophe> q+ <bramus> … how to resolve the rules inteh block <emilio> ... So re. what happens for all browsers, are we going to lose all the rules <bramus> … same solution with @layer can be applied <emilio> ... but we could make like @layer where anything after is considered part of it <emilio> ... so this looks a lot about @layer <emilio> ... just with no notion of priority\ <fantasai> emilio: Concern is not only with what's in the block <bramus> emilio: concern is not only what happens with contents of the blocks but older browser dont have concept of importing parts of a stylesheet <bramus> … external parts would apply <bramus> matthieud: doesnt work for ??? <bramus> emilio: but doesnt work for link either <ydaniv> q- <emilio> s/???/@import <astearns> acj justinf <emilio> ack justin <emilio> justinf: Wanna comment on the fragment thing <matthieud> I would have like an answer about the @layer vs @sheet though ? <emilio> ... has been touched that the impolicit URL is the HTML document url <emilio> ... being able to do about dom vs. stylesheet <emilio> ... on the DSD case there could be multiple sheets <emilio> ... and in order to do this we have to have a central resource <emilio> ... and I'd be a bit wary of this <emilio> ... there's also a question of external stylesheets with nested @sheets <emilio> ... it's something I'd want to avoid, we're trying to avoid global resources like custom element names or what not <emilio> ... so I wouldn't add another one <astearns> ack florian <emilio> florian: narrowly on this specific slide, as long as @sheet is something that exists I agree it'd be nice to use it on inline styles <noamr> For the `#` - it can be `#:~:sheet=the-sheet-name` like text fragments <emilio> ... slightly more generally I think this is quite complex and we need to move into the discussion of what this does for shadow dom <emilio> ... yeah it's convenient to have one file with preprocessing <emilio> ... http/2 deals with some of the multiple request complexity <astearns> ack emilio <justinf> for shadow DOM basic bundling is sufficient, IMO <florian> s/use it on inline styles/use it on inline style elements <emilio> ... so outside of shadow dom I don't see a lot of use for this <bramus> emilio: agree with florian that main use case feels … basically about shadow dom. if you have no, you can bundle and call it a day <bramus> … want to try a counter proposal tha tmight work <bramus> … and doesnt need to add anything new <bramus> … except 1 thing <bramus> … what you really want is @import but without separate request to import into shadow dom <bramus> … talked about removing constructbile stylesheet restircition in adoptable ones <bramus> … if you have data-uri @import that you could import into SD you kinda get this behavior <bramus> … not user friendly, but if use case is bundlers then they can prolly manage <bramus> … idea would be to get the @import stylesheet and shadowroot.adopted.push(…) <bramus> … and if you dont want that to aply to the doc, you could isable with a non-mathcing media in the elem <justinf> q+ <bramus> … we have a lot of similar pieces that would be nice <bramus> … if use cases are narrow, e.g shadow dom and bundling <bramus> … then you might be able to get away with this <bramus> … has that been explored? <bramus> q? <justinf> isn't that unwinding the whole proposal, including the previous resolutions? <emilio> yes <astearns> ack castastrophe <justinf> `@sheet` seems a lot simpler than data URI and changes to import to me <emilio> castastrophe: just a question, trying to picture things in the design systems space <emilio> ... how would you import multiple sheets, multiple `<link>` or `@import`? <emilio> kschmi: yeah you'd need multiple sheets or @import or both <astearns> ack justinf <emilio> justinf: Responding to emilio or florian... The basic @sheet to me is very simple <emilio> ... there's no way currently to include an inert chunk of CSS <emilio> ... turns out you can with @supports <emilio> ... but @import + data uri + ... feels a lot more complex than @sheet <emilio> ... The additional complexity is adding ways to reference these from inline styles <emilio> ... I don't think that complexity applies to that part of the proposal <emilio> FWIW `@import url("data...") not all;` doesn't seem /terribly/ complex to me <emilio> kschmi: so re. shadow dom <justinf> but then you need that `@import()` to 1) be inert, and 2) be importable as a separate sheet <emilio> ... current mechanism are duplicate `<link rel>` or inline styles or script-based adoptedStyleSheets <emilio> ... so for declarative shadow DOM is not great <emilio> ... If we support the standalone fragment we can support it for declarative shadow dom <emilio> ... that's kinda why this is relevant to DSD <emilio> ... solves that messy problem r/n <noamr> q+ <emilio> ... big question justinf is concerned about is scoping <justinf> q+ <emilio> ... which is an issue, might be the same as inheriting from parent <emilio> ... lots of open issues, we have an explainer in MSEdgeExplainers <emilio> ... big list of open issues, but key problem we're solving is inline styles with declarative shadow dom <emilio> ... another solution for this would be declarative CSS modules <emilio> ... `<script type=css-module>` and `adoptedstylesheets=""` <emilio> ... TAG pointed to `@sheet` <emilio> ... seems this still has more issues <emilio> ... If we could get this standalone fragment thing would be nice <emilio> ... both seem good proposals, but I think there's a big demand to solve this <emilio> ... so there's shared goals, but they can solve the same problem <emilio> ... curious to see what the WG and developers prefer <emilio> ... that was more or less it <emilio> q+ <emilio> ack noamr <justinf> noam +1 <emilio> noamr: When I see this whole thing I see it like an HTML problem and not a CSS problem <emilio> ... You can fix this with shadow DOM if you have a fragment refer to an ID in your document <emilio> ... it seems also a problem with script importing <fantasai> s/ID/ID of a <style> or <link> element/ <emilio> ... maybe we can present this at WHATNOT <fantasai> +1 noamr <emilio> ... But I wonder if there are commonalities to importing style and script <emilio> ... and there are solutions that could require less work <emilio> kschmi: Yeah if there was a way like svg fragment you're right we wouldn't need @sheet for this <justinf> the only issue with IDs with DSD is that we need a *global* ID to cross shadow root boundaries. But that's a DOM issue <emilio> ... We could have an attribute <emilio> noamr: you'd add a link pointing to the ID <castastrophe> q+ <astearns> ack justinf <emilio> justinf: re. the scoping, one of the reasons I was shaking my head with scoping <emilio> ... we want to render instances, in a way that the root needs to hold the stylesheet of component a, but you don't want to emit them until you've found the first <emilio> ... so I think we need some sort of global resource <emilio> ... but I'd be very careful about choosing what global resource <noamr> for bundling, you can have an external HTML file that has multiple <style> elements with IDs and you refer to them <emilio> ... but I agree with noamr that this is kind of an HTML issue, because IDs don't propagate across shadow boundaries <bramus> emilio: wanted to ask whether other subresources have same nees <bramus> … but tha t is what noam ended up asking <astearns> ack emilio <astearns> ac castastrophe <astearns> ack castastrophe <emilio> castastrophe: had a question about @sheet, the syntax makes me think that if I wanted to override a sheet namespace I would be able to <emilio> ... with the fragment syntax it makes me feel like you can't <emilio> ... if I declare another ID in the DOM it doesn't override the first <emilio> ... what is the behavior here? <emilio> kschmi: That's one of the open questions <florian> q+ <emilio> ... @layer would add to it <astearns> ack fantasai <astearns> ack florian <emilio> florian: I find the shadow dom use case very compelling <emilio> ... more compelling than the other use cases <emilio> ... if we agree to solve it with @sheet it motivates solving some of the `@sheet`s <emilio> ... issues <emilio> ... the way @sheet is imported seems problematic <emilio> ... browsers doing different things for `url(#foo)` seems like a problem <emilio> ... the overriding is question is a challenge as well <castastrophe> q+ <emilio> ... the shadow dom use case seems the most compelling, the other ones seem nice <emilio> ... if we decide to solve the shadow dom use case some other way, not sure we want `@sheet` <justinf> this difference in behavior with legacy browser is always the case... I'm personally hoping that @sheet support can coincide with CSS imports support in Webkit and Gecko so that if you can import a stylehsheet you can also import an `@sheet` <emilio> kschmi: Great points, I think the original proposal was about importing / bundling <noamr> justinf: I think hash-fragments, e.g. in same-document links, cross shadow boundaries? <emilio> justinf: this is an addon to JS import asserts in CSS modules <emilio> ... you have a lot of JS modules which depend on small fragments on CSS <emilio> ... but bundlers don't know how to deal with bundling CSS there <emilio> ... that was my main motivation, you end up with lots of small CSS files otherwise <emilio> ... was kinda hoping that if @sheet is simple enough it'd ship along CSS imports in webkit / gecko <miriam> q+ <emilio> ... happens to be a simple polyfill for transforming to @import <astearns> ack castastrophe <justinf> transforming to @supports, not @import <emilio> castastrophe: I see where you're coming from florian <emilio> ... if we solve it for webcomponents my preference would be to solve it for native DOM solutions as well <bramus> Big +1 <emilio> ... I'm doing so much transforming of code between the two systems, so it'd be nice to allow authors to just write it once <astearns> ack miriam <justinf> btw, CSS imports is mainly a feature that makes CSS more usable from JS defined components... it doesn't need to be web components or shadow DOM <emilio> miriam: high level syntax thought, there was some mention of syntax looking similar to @layer, but funcitonality is entirely different <emilio> ... I think it overlaps more with @scope <justinf> q+ <noamr> +1 <emilio> q+ <emilio> kschmi: Yeah the way I think about @sheet is a separate file <matthieud> actually yes I agree, @scope is closer to this than @layer <emilio> ... @layer is a different cascade layer, and that's why you can have multiple layers and so on <emilio> ... @sheet is only one definition per sheet, that kinda helps my mental model a bit <emilio> matthieud: I agree that @scope is closer than @layer <emilio> ack justinf <astearns> ack justinf <emilio> justinf: Wanted to comment, I wanted to make sure that this is not always associated with shadow dom and webcomponents <emilio> ... having a way to import this seems useful for non-shadow-dom related use cases as well <emilio> ... so I'm hoping this would be much broader <bramus> (FWIW: I believe @layer was only mentioned in relation to what browsers do when they don’t support it: they discard the entire block.) <emilio> ack emilio <astearns> ack emilio <bramus> emilio: want to suggest that if we are doing this we could bypass a lot of the fragment issues if we allow importing using a different syntad <emilio> @import sheet(name) <bramus> s/syntad/syntax <bramus> emilio: that bypasses a lot of the questions about what the fragment means <castastrophe> or both? @import url() sheet() <florian> +1 <bramus> justinf: still seems to have the global namespace <weinig> (not sure if this has been mentioned, or how relevant it is, but there is a some written thoughts on fragments here -> https://www.w3.org/TR/fragid-best-practices/) <bramus> emilio: that’s kinda ??? <emilio> castastrophe: +1 to emilio, you could combine it with url and specify different sheets from that URL <bramus> emilio: that wouldn have global namespace issues <bramus> … because you arkimporting this sheet from that url <bramus> justinf: depends on … declarative dom use case (missed) <bramus> emilio: guess you could with no URL you import the document or some smaller thing <bramus> … if you ignore the improt and inline style hting, it still works for declarative shadow dom <noamr> Perhaps "importing from inline" and "partially importing from a sheet" don't require the same solution? <bramus> … do `@import url() sheet()` <bramus> justinf: if you can do that, solves 99% of ht eproblems <bramus> … if you can bundle all, you can do ahead of time and import later <noamr> q+ <justinf> q+ <bramus> kurt: challenge with file specific syntax is what justin was saying – need to support same doc styles <astearns> Zakim, close queue <Zakim> ok, astearns, the speaker queue is closed <bramus> … you want a high per site to paint auickly with styles <bramus> … best option is not an external file <bramus> … that is feedback i got from devs <bramus> … "sure separte file is nice, but inline in html is powerful for first paint" <astearns> ack noamr <emilio> `<style>@import url(..) sheet(..)</style>` <bramus> noamr: seems like different problem? <astearns> ack justinf <emilio> justinf: wanted to clarify on `<stlye>`. In a server component case you don't have all the components, they depend on the page <emilio> ... something like an amazon product page is a canonical example <emilio> ... could render millions of components <emilio> ... I don't think any external file solution deals with that <bramus> emilio: they are not exclusive <bramus> … as noam was saying, having a specific syntax to import sheets and being able to import from an inline style seem like differnet <bramus> justinf: agree <bramus> … would love to see capabitliy in html <bramus> emilio: ok <bramus> … then we are in agreement <bramus> florian: you emilio are proposing to solve with css syntax, not html <bramus> emilio: i was proposing to have specific syntax for importing style sheet from a file <bramus> … tha tdoes not avoid adding that fro m??? <bramus> florian: if you have @import url() sheet() it imports tehs eet fro,m the url <bramus> … if you omit the url, its from the current file <bramus> … if the curernt file is the html, then that is where you try and go find it <bramus> emilio: or you could impor from url(#something) to refer to that style or link <castastrophe> q+ <bramus> florian: the syntax you proposed not only is useful but fully replaces need for link rel=stylesheet and makes it not an html problem <bramus> emilio: still need to define how to target a partciular element <noamr> import url("#my-inline-style") sheet(my-sheet) <bramus> castastrophe: if you are inside sd with import, do you have timport @import from sd or from parent? <bramus> … does not exist right now <bramus> noamr: url fragment are not ??? <bramus> astearns: should prolly close this for now <emilio> noamr: URL fragments do cross shadow boundaries, like `<a href="#foo">` doesn't look only inside its shadow tree <bramus> … was mentionedthat this should be presented at whatnot <bramus> … kurt, can you do that? <bramus> kurt: yes <bramus> astearns: and then we ahve issue of @sheet not being a spec <bramus> … would you kurt be intereste to be an editor for that? <bramus> kurt: yes <emilio> s/kurt/kschmi/ <bramus> astearns: So I proposed to add kschmi as editor for css-cascade-7 to spec that <bramus> … start with what we have not, and then extend to shadow dom and othe ruse cases and bring back to the group <bramus> kschmi: sgtm <bramus> TabAtkins: the number? <bramus> astearns: taking that from fantasai that @scope is prolly done and to take 6 to CR <bramus> TabAtkins: if 6 is ready for cr and 5 is in cr, then merge scope into 5 <bramus> … dont like many numbers, especially when its only 1 feature per number <bramus> fantasai: we should get 4 in rec bc layers are shipping and 6 should move to cr and merge down contents of 5 into 6 <bramus> PROPOSED RESOLUTION: Add kurt as editor of css-cascade and work with current editors to figure out the number <bramus> florian: IUC we resolved on adding @sheet syntax itself, but not on the importing part <bramus> … regardless we have had enough debate about that that we should add an inline issue in the spec <bramus> … that its a moving target <bramus> astearns: editor’s discretion <bramus> RESOLVED: Add kurt as editor of css-cascade <bramus> astearns: let’s move on to shape issues <justinf> thank you everyone! |
Link to explainer
CSS
@sheet
is a mechanism for bundling multiple CSS stylesheets into one .css file. There are numerous practical advantages to bundling multiple CSS sheets into one file, including reduced network requests and potentially increased compression ratios.@sheet
is an at-block with an identifier:style.css:
Sheets defined via
@sheet
can be referenced via fragment identifiers in URL's that match the@sheet
identifier:<link rel="stylesheet" href="style.css#sheet1">
This was discussed in the CSSWG call on 2023-04-05 as well as this discussion.
We propose expanding this definition to include
@sheet
definitions at the document level, which can similarly be referenced via a local fragment:Much like anchor fragments, Shadow DOM nodes can access
@sheet
definitions from their parent scope:More details and examples can be found in the explainer link above. I would welcome any comments/suggestions/additional use cases, either in this thread or as issues in the MSEdgeExplainers repo: New issue
The text was updated successfully, but these errors were encountered: