Skip to content
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

Open
KurtCattiSchmidt opened this issue Jan 15, 2025 · 24 comments
Open

Proposal: CSS @sheet #11509

KurtCattiSchmidt opened this issue Jan 15, 2025 · 24 comments

Comments

@KurtCattiSchmidt
Copy link

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:

@sheet sheet1 {
 ...
}

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:

<style>
@sheet sheet1 {
 ...
}
</style>
<link rel="stylesheet" href="#sheet1">

Much like anchor fragments, Shadow DOM nodes can access @sheet definitions from their parent scope:

<style>
@sheet foo {
  div {
    color: red;
  }
}
</style>
<template shadowrootmode="open">
  <link rel="stylesheet" href="#foo" />
  <span>I'm in the shadow DOM</span>
</template>

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

@jyasskin
Copy link
Member

jyasskin commented Jan 18, 2025

FWIW, a fragment pointing into an HTML file seems like the wrong way to refer to @sheet declarations inside inline CSS inside that HTML file. Specifically, fragment resolution in URLs depends on the MIME type of the resource (https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-indicated-part-of-the-document, https://www.rfc-editor.org/rfc/rfc8820#name-uri-fragment-identifiers). Inside an HTML document, fragments point to the element with a matching 'id' or <a name> attribute, or the text identified by https://wicg.github.io/scroll-to-text-fragment/#invoking-text-directives. That won't find an @sheet.

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).

@andruud
Copy link
Member

andruud commented Jan 20, 2025

Will there be a restriction on where @sheet is allowed? Only top-level, and before @import?

@astearns astearns moved this to FTF agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from FTF agenda items to Wednesday morning in CSSWG January 2025 meeting Jan 27, 2025
@KurtCattiSchmidt
Copy link
Author

Will there be a restriction on where @sheet is allowed? Only top-level, and before @import?

Yes, there are restrictions on where @sheet is allowed. You can think of each @sheet conceptually as a separate file , so they would have to be top-level (and not nestable).

This was discussed here: #5629 (comment)

The discussion around @import in that thread was mostly about importing the @sheet fragment, not necessarily the ordering rules between @sheet and @import. Given that @import currently needs to be before any other at-rules, we should be able to keep this behavior for @sheet.

@romainmenke
Copy link
Member

romainmenke commented Jan 28, 2025

Good proposal 👍
Thank you for raising this!


@sheet represents an inlined .css file, right?
So shouldn't this match @import in as many ways as possible?
They should be equivalent and there shouldn't be syntactic benefits or drawbacks to either.

With that in mind I think that nesting should be allowed and that using @import in @sheet should also be allowed.

These should all be equivalent:

1:

index.css

@sheet foo {
  @sheet bar {}
}

2:

index.css

@sheet foo {
  @import "bar.css";
}

3:

index.css

@import "foo.css";

foo.css

@import "bar.css";

Is there a reason we can't do this?


I agree that for the order @sheet should be valid anywhere @import is.


<link rel="stylesheet" href="style.css#sheet1" is this web compatible?
Might need a use counter to check if fragments in stylesheet urls aren't already in use.

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.
Most CSS authors will write in multiple files but bundle to avoid a waterfall.
They however won't be importing a single sheet. They will want to load and apply everything.

Having @sheet would allow bundlers to avoid other gnarly hacks.
Especially when relative imports are mixed with resources loaded from a 3rd party:

@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 it could be:

@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.
Typed and untyped custom props also have different behavior.

Maybe it makes sense to also have a @base rule?
To match <base href="https://www.example.com/" />

This @base rule could be used by CSS authors but is mostly intended to be inserted by bundlers.

This would allow all relative urls to remain as they were written without any unexpected behavior differences between bundled or unbundled stylesheets.

Before bundling:

https://www.example.com/public/styles/foo.css
https://www.example.com/public/images/bar.jpg

:root {
  background: url(../images/bar.jpg);
}

When bundled the relative urls will break unless there is some provision:

https://www.example.com/public/index.css
https://www.example.com/public/images/bar.jpg

@sheet {
  @base url("https://www.example.com/public/styles/");

  :root {
    background: url(../images/bar.jpg);
  }
}

I think it would be ideal if @sheet could be used to fully and accurately represent any graph of @import statements in a single file.

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 @sheet could reduce the number of hacks needed to implement a CSS bundler correctly.
Which in turn would make it easier for CSS authors to pick a tool that actually works.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Proposal: CSS @sheet, and agreed to the following:

  • RESOLVED: Add kurt as editor of css-cascade
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!

@KurtCattiSchmidt
Copy link
Author

@sheet - CSSWG f2f.pdf - here is a PDF version of the slides I presented at the F2F.

@KurtCattiSchmidt
Copy link
Author

Good proposal 👍 Thank you for raising this!

Glad you like it! 👍 I appreciate your thoughts and suggestions and took some time going over them.

@sheet represents an inlined .css file, right? So shouldn't this match @import in as many ways as possible? They should be equivalent and there shouldn't be syntactic benefits or drawbacks to either.

You're correct that @sheet has a lot of similarities with @import, in particular that they both bring in style rules from a separate file, but the real power of @sheet is that it binds a set of rules to an identifier that can be imported in contexts beyond CSS. This identifier is really important, as it allows @sheet blocks to be imported in different contexts (e.g. <link rel>, @import, and CSS Modules). Conceptually, you can think of each @sheet block as a separate CSS file that gets represented by its @sheet identifier instead of a file name.

With that in mind I think that nesting should be allowed and that using @import in @sheet should also be allowed.

These should all be equivalent:

1:

index.css

@sheet foo {
@sheet bar {}
}

If this were to be referenced by a <link rel> tag, how would you target bar? We could differentiate nested sheets with some sort of delimiter (e.g. if we used # to delimit between nested sheets this could be valid - <link rel="stylesheet" href="index.css" sheet="foo#bar">), but I am struggling to come up with a use case. What types of situations would nested @sheet definitions enable?

2:

index.css

@sheet foo {
@import "bar.css";
}

This seems valid to me. I know that there are rules around @import that we'd need to respect, but I think @import should be able to work as the first / only statement of an @sheet.

3:

index.css

@import "foo.css";
foo.css

@import "bar.css";
Is there a reason we can't do this?

This looks valid to me too.

I agree that for the order @sheet should be valid anywhere @import is.

<link rel="stylesheet" href="style.css#sheet1" is this web compatible? Might need a use counter to check if fragments in stylesheet urls aren't already in use.

The CSSWG decided at the F2F last week to not go with URL fragments for binding to @sheet identifiers, so we're now looking into adding an attribute to <link> tags to specify which sheet is being imported as well as adding an optional identifier to @import for similar functionality there (e.g. @import sheet1 from "style.css";).

I know that current frameworks (vite? or vue?) already use this.

That's great context, I appreciate it!

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.

Could you explain this a bit more? I don't understand how bundling is impossible without anonymous sheets. Also, how could anonymous sheets get applied later? Keep in mind that any rules under an @sheet block don't get applied by default - they are only applied once they are imported directly by identifier. Without an identifier to be imported later, it seems that these rules would be lost.

All CSS authors should be able to benefit from this feature, not only those using shadow dom. Most CSS authors will write in multiple files but bundle to avoid a waterfall. They however won't be importing a single sheet. They will want to load and apply everything.

Having @sheet would allow bundlers to avoid other gnarly hacks. Especially when relative imports are mixed with resources loaded from a 3rd party:

@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 it could be:

@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. Typed and untyped custom props also have different behavior.

Keep in mind that @sheet contents do not apply by default. So for these examples, you need an identifier, even if it's throw-away. So your example would look like:

@sheet sheet1 { /* contents of foo.css */ } /* Define sheet1 rules */
@import "sheet1";                                      /* Apply sheet1 rules */
@import "https://some-framework.com/index.css";
@sheet sheet2 { /* contents of bar.css */ }           /* Define sheet2 rules */
@import "sheet2";                                      /* Apply sheet2 rules */

Does that fundamentally change your bundling scenario? Also, is this something existing @layer functionality could help with? I appreciate the scenarios you've provided and definitely want to make this feature useful! I don't have a lot of experience with bundling so this is super helpful context.

Maybe it makes sense to also have a @base rule? To match <base href="https://www.example.com/" />

This @base rule could be used by CSS authors but is mostly intended to be inserted by bundlers.

This would allow all relative urls to remain as they were written without any unexpected behavior differences between bundled or unbundled stylesheets.

Before bundling:

https://www.example.com/public/styles/foo.css https://www.example.com/public/images/bar.jpg

:root {
background: url(../images/bar.jpg);
}
When bundled the relative urls will break unless there is some provision:

https://www.example.com/public/index.css https://www.example.com/public/images/bar.jpg

@sheet {
@base url("https://www.example.com/public/styles/");

:root {
background: url(../images/bar.jpg);
}
}
I think it would be ideal if @sheet could be used to fully and accurately represent any graph of @import statements in a single file.

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 @sheet could reduce the number of hacks needed to implement a CSS bundler correctly. Which in turn would make it easier for CSS authors to pick a tool that actually works.

These are great suggestions and I really appreciate the perspective from someone who has experience with bundlers! It seems like another use case for some sort of a markup-based equivalent of import maps, and this is close to it. This seems very useful well beyond @sheet, so it might make sense to propose as a separate CSS feature.

@astearns
Copy link
Member

astearns commented Feb 4, 2025

@sheet - CSSWG f2f.pdf - here is a PDF version of the slides I presented at the F2F.

And just in case, here’s a w3.org link: https://lists.w3.org/Archives/Public/www-archive/2025Feb/att-0000/_sheet.-.CSSWG.f2f.pdf

@robglidden
Copy link

robglidden commented Feb 5, 2025

The CSSWG decided at the F2F last week to not go with URL fragments for binding to @sheet identifiers, so we're now looking into adding an attribute to tags to specify which sheet is being imported as well as adding an optional identifier to @import for similar functionality there (e.g. @import sheet1 from "style.css";).

Excellent changes to the explainer clear up a lot of the confusion I have been having with this proposal!

As I understand it, to reference a sheet in a style element:

<style id="sheet">
@sheet foo {
    div {
    color: red;
    }
}
</style>

instead of an (overloaded) fragment-only identifier:

<link rel="stylesheet" href="#foo" />

you would use the id of the style element plus a new "sheet" attribute:

<link rel="stylesheet" href="#sheet" sheet="foo" />

with similar syntax for @import, import attributes / CSS Modules and CSS files / network resources.

And by deciding that @sheets must be explicitly imported, instead of imported by default (#934), style rules outside of @sheets are sensibly referenced as:

<link rel="stylesheet" href="#sheet" />

Correct?

And if I want a style element (rules outside of sheets) to be available to be referenced in a shadow root but not automatically applied in the light DOM, I would just use <style disabled>?

All this seems to avoid a lot of backward compatibility and adoption issues that could have arisen from the previous version of the explainer.

And doesn't this in essence potentially address the awkwardly overloaded specifier attribute of the Declarative CSS Module proposal #10673, opening a syntax alignment path to merge some or all of the functionality of the two proposals?

So doesn't this also resolve/avoid the FOUC problem of merging multiple @sheet definitions with the same identifier (#937), because there is now no need or mechanism to merge sheets from multiple style elements or CSS files (like @layer does)?

Also, I'd suggest that in addition to:

<!-- The following two link tags should only make a single network request. -->
<link rel="stylesheet" href="sheet.css" sheet="foo" />
<link rel="stylesheet" href="sheet.css" sheet="bar" />

this should also only make a single network request:

<link rel="stylesheet" href="sheet.css" />

Otherwise, for both cases, particularly when the links are repeated in multiple shadow trees, it seems there will still be an unspecified and browser-specific reliance on caching for implementation that can produce FOUC.

@mayank99
Copy link

mayank99 commented Feb 6, 2025

The CSSWG decided at the F2F last week to not go with URL fragments for binding to @sheet identifiers, so we're now looking into adding an attribute to <link> tags to specify which sheet is being imported as well as adding an optional identifier to @import for similar functionality there (e.g. @import sheet1 from "style.css";).

@KurtCattiSchmidt Is there a link to a resolution somewhere? And does this mean CSSWG is walking back on its previous resolution?

Just for clarification, are all three of the following cases disallowed now?

  1. <link rel="stylesheet" href="/styles.css#sheet1">
  2. import sheet1 from "/styles.css#sheet1" with { type: "css" };
  3. <link rel="stylesheet" href="#sheet-in-same-document">

My previous understanding was that 1 and 2 were fine, but only 3 was problematic.


In the updated explainer, I'm seeing this snippet:

<link rel="stylesheet" href="#sheet" sheet="foo" />

If you ignore the sheet attribute, doesn't href="#sheet" imply that you can link a <style id="sheet"> in the same document? That should probably be its own proposal/issue, as it seems useful even without @sheet.

@KurtCattiSchmidt
Copy link
Author

@robglidden -

Correct?

Yes, that all looks correct to me.

And if I want a style element (rules outside of sheets) to be available to be referenced in a shadow root but not automatically applied in the light DOM, I would just whatwg/html#10710 (comment) <style disabled>?

disabled also means disabled in the shadow root, so this current proposal requires the usage of @sheet for defining styles but not applying them.

And doesn't this in essence potentially address the whatwg/html#10673 (comment) whatwg/html#10673 (comment) of the Declarative CSS Module proposal whatwg/html#10673, opening a syntax alignment path to merge some or all of the functionality of the two proposals?

Yes, @sheet provides a clear separation between the definition and application of styles. Agreed that both proposals can address sharing styles with Shadow DOM - we were directed towards using @sheet from the TAG review: "To allow these styles to be defined inline, @sheet seems like a better solution." w3ctag/design-reviews#1000 (comment)

Otherwise, for both cases, particularly when the links are repeated in multiple shadow trees, it seems there will still be an unspecified and browser-specific reliance on caching for implementation that can produce FOUC.

This won't change the underlying caching behavior for external files, but one of the reasons we're so interested in inline style definitions is to avoid this type of FOUC.

@KurtCattiSchmidt
Copy link
Author

@mayank99 - we didn't formally resolve to eliminate the filename + fragment syntax, but we discussed revisiting it in the minutes here: #11509 (comment)

I don't think the fragment-for-sheet resolution makes as much sense with the new proposal to add a sheet attribute. We could proceed with the fragment syntax for external files only, but there are two issues with this:

  1. It only works with external files, and only ever will due to the MIME type mismatch between the stylesheet and HTML document
  2. There would be two ways to embed a specific @sheet for external files in a <link> tag, which seems redundant

But since there was already a formal resolution to the fragment syntax, we'll need another resolution to redefine it. I will propose this at a future CSSWG meeting.

If you ignore the sheet attribute, doesn't href="#sheet" imply that you can link a <style id="sheet"> in the same document? That should probably be its own proposal/issue, as it seems useful even without @sheet.

Yes, exactly! I will propose this as a separate proposal from @sheet and link to it here when that happens.

@romainmenke
Copy link
Member

romainmenke commented Feb 9, 2025

@KurtCattiSchmidt said:

Keep in mind that @sheet contents do not apply by default. So for these examples, you need an identifier, even if it's throw-away. So your example would look like:

Does that fundamentally change your bundling scenario? Also, is this something existing @layer functionality could help with? I appreciate the scenarios you've provided and definitely want to make this feature useful! I don't have a lot of experience with bundling so this is super helpful context.

I only just now realized how @sheet and @import can indeed be used side by side.
How you can inline with @sheet while keeping the @import statements in the intended order.
This only requires rewriting the @import statements so that they refer to the @sheet instead of a file.

Thank you for clarifying that.

(@layer can not be used to make bundled CSS more correct)


With that in mind I think that nesting should be allowed and that using @import in @sheet should also be allowed.

If this were to be referenced by a <link rel> tag, how would you target bar? We could differentiate nested sheets with some sort of delimiter (e.g. if we used # to delimit between nested sheets this could be valid - <link rel="stylesheet" href="index.css" sheet="foo#bar">), but I am struggling to come up with a use case. What types of situations would nested @sheet definitions enable?

I think I am looking at this from a different perspective.

It is not so much that there is a specific need or use case for nested @sheet. Something that is only possible by having nested sheets.

Rather I think that it is something people will do. Either organically, automated by a tool or because they are not the only author.

A CSS author might write:

@sheet foo {
  @import url("some-cdn.com/bootstrap.css");
}

And bootstrap.css might have:

@sheet bootstrap { /* css */ }

This would result in a nested sheet, right?

I don't think there is a good reason to disallow this.


I've filed a separate issue for my idea for a @base statement: #11680

@robglidden
Copy link

@KurtCattiSchmidt:

"To allow these styles to be defined inline, @sheet seems like a better solution"....
... This won't change the underlying caching behavior for external files, but one of the reasons we're so interested in inline style definitions is to avoid this type of FOUC.

I think I am just reiterating that same TAG review comment, which also said as to "why <link> or @import cannot be used for sharing styles across shadow roots", "perhaps the issue can be addressed at the root, by specifying that these requests MUST be deduplicated, either by default (if web compatible) or with a certain flag set".

But even more fundamentally, there seems to be an expectation that needs to be clearly specified across @sheets and declarative CSS modules that multiple references from anywhere to a DOM element (similarly for multiple references to a network resource, i.e. a file) should refer to the same copy, instance, or original source of the underlying resource, not (potentially) different ones.

That seems to be the essence of "sharing" styles and potentially other resource types.

Like another comment in that TAG review said in a somewhat different context:
"... that there is an existing behavior of copy-on-write behavior when the same stylesheet is loaded from multiple places. e.g. if I <link> a.css twice, there's one instance in RAM ..."

This is indeed how SVG <use>, which can reference a DOM element in the same document (as well as a network resource), already behaves:

<svg
   id="svgWithMyCircle"
   viewBox="0 0 30 10"
   xmlns="http://www.w3.org/2000/svg"
>
   <circle id="myCircle" cx="5" cy="5" r="4" stroke="blue" />
</svg>
<svg id="svgWithUse" viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
   <!-- Reference to circle element -->
   <use href="#myCircle" fill="yellow" />
</svg>
<button onclick="ChangeOriginalMyCircle()">Change Original MyCircle</button>
<script>
   function ChangeOriginalMyCircle() {
   const myCircle = document.getElementById("myCircle");
   myCircle.setAttribute("stroke", "red");
   }
</script>

In the example above, clicking the button changes the stroke color of the circle in both the first and second SVG. This is because the <use> element references the same instance of the circle element in the first SVG.

So I am also suggesting that in a new proposal, <link rel="stylesheet" href="#sheet" /> should behave similarly and be backed by the original element itself.

Note that means that import sheet from '#sheet' with {type: "css"} should also be backed by the original element itself, which is a bit different from how importing a network resource necessarily refers to a singleton instance.

Otherwise, <link rel="stylesheet" href="#sheet" /> and import sheet from '#sheet' with {type: "css"} could refer to different things in the same document.

@bramus
Copy link
Contributor

bramus commented Feb 10, 2025

@robglidden FYI: During the recent discussion at the F2F (see notes here) the case against using fragment identifiers to refer to a @sheet was made.

@robglidden
Copy link

@bramus

Yes, in the longer thread above I think I am responding to what I think is @KurtCattiSchmidt's interpretation of how to potentially address that same F2F discussion/decision:

The CSSWG decided at the F2F last week to not go with URL fragments for binding to @sheet identifiers, so we're now looking into adding an attribute to tags to specify which sheet is being imported as well as adding an optional identifier to @import for similar functionality there (e.g. @import sheet1 from "style.css").

Are you and @KurtCattiSchmidt talking about the same thing? I am assuming @KurtCattiSchmidt meant that <link rel="stylesheet" href="#reference-straight-to-an-atsheet-inside-a-style-element" /> was out? So the explainer was updated to consider <link rel="stylesheet" href="#sheet" sheet="foo" />? With a potential new proposal to flesh out the natural consequences of thereby enabling <link rel="stylesheet" href="#sheet" />?

Please correct my misunderstanding.

@robglidden
Copy link

robglidden commented Feb 10, 2025

Also, in case this is also a source of confusion, for consistency I have been using the same identifier names as the original and updated explainer:

<style id="sheet">
@sheet foo {
  div {
    color: red;
  }
}
</style>

Where "#sheet" is not a URL fragment identifier to a sheet, but the id of the style element that contains a sheet. "#foo" is the identifier of the sheet inside the style element.

I see people calling any other CSS rules in the #sheet id style element that are not inside a @sheet block "rules outside of @sheets", so I am too. So <link rel="stylesheet" href="#sheet" /> in explainer terminology perhaps confusingly doesn't refer to @sheets at all, but rules outside of @sheets.

@mayank99
Copy link

mayank99 commented Feb 10, 2025

From what I understand, there are arguments against using URL fragments but it hasn't been rejected completely.

The main concern is the MIME type mismatch. It makes sense that page.html#id is expected to match an element in HTML (rather than a @sheet). However, this issue does not apply to styles.css#sheet, so I don't think it should be rejected.

@sheet solves the problem of bundling multiple stylesheets into a single file, and importing individual sheets as needed (from HTML/CSS/JS, all without any new syntax/APIs!). It's "just" a URL.

<link rel="stylesheet" href="/styles.css#sheet1">
@import "/styles.css#sheet1";
import sheet1 from "/styles.css#sheet1" with { type: "css" };

There was another important point made during the F2F, which I think should be considered again:

<@noamr> Perhaps "importing from inline" and "partially importing from a sheet" don't require the same solution?

Here, @sheet with fragment URLs solves the problem of "partially importing from a sheet".

For solving the declarative shadow DOM problem ("importing from inline"), I believe <link rel="stylesheet" href="#style-element"> would go a long way, without complicating @sheet. I'm looking forward to @KurtCattiSchmidt opening a dedicated issue for href="#style-element".


There is the advanced DSD use-case where an "inert stylesheet" needs to be emitted into light DOM and imported into shadow DOM. I believe this is at least partially solved by existing and emerging concepts:

  1. For external CSS files, preload/prefetch using <link>, then set the media="not all" attribute (if the styles are not already scoped). This will help with FOUC when you request it later (e.g. from a JS component).
  2. For same document, emit inline <style> elements with unique IDs. To prevent the styles from having any effect in light DOM, wrap them with :host. This could be achieved with a build-time transformation. Then, from within shadow DOM, <link> to those style elements using the newly-proposed href="#style-element" syntax.
    1. When @scope is available, this will become much nicer: Styles wrapped with@scope (:host) will only match in shadow DOM, and :scope can be used to refer to :host.
    2. (Hypothetical) I've seen mentions of @import and <link> potentially supporting scope (i.e. "importing a stylesheet into a scope"). Maybe <style> could have something similar, which would make it even nicer.

For a proper solution for this "inert"/"streaming DSD" use-case, probably a different avenue needs to be explored (e.g.. whatwg/html#10673). @sheet seems like it's better at solving the "bundling" use-case; shoehorning it into solving the DSD problem might result in the worst of both worlds.

I also agree with the comment that @robglidden linked to, i.e. the duplication problem should be "addressed at the root, by specifying that these requests MUST be deduplicated". This would make styles.css#sheet much more powerful.

@noamr
Copy link
Collaborator

noamr commented Feb 11, 2025

I've jotted down a mental model for this after the F2F.

I think importing scripts and styles should work in a similar fashion.

  • Importing scripts also has the issue of importing from an inline script.
  • The @sheet proposal is equivalent to importing a specific export from a script.
  • So, importing a @sheet should have a different syntax from importing from a <style>. They're orthogonal and can work together.

So starting from the current way to partially import from a script:

// script.js
export const something = "foo";

// importing
import {something} from "script.js"

I'd suggest that importing a style from an external style, with @sheet, should look something like this:

// sheet.css
@sheet mysheet {
  ...
}

// importing
@import mysheet from "sheet.css";

Or

<link rel=stylesheet href="sheet.css" sheet="mysheet">

In addition, as a separate issue, we can allow importing a script from an inline script:

<script id="bundle" type="module">
  export const something = "foo";
</script>

<script type="module">
  import {something} from "#bundle";
</script>

And extend it to style, allowing the use case of importing a whole inline style into shadow DOM (irrespective of @sheet):

<style id="theme">
  * {
    --primary-color: rebeccapurple;
  }
</style>

<my-element>
  <template shadowrootmode=open>
    <style>
      // this imports the entire contents of `<style id=theme>`
      @import "#theme";
    </style>
    <!-- or -->
    <link rel=stylesheet href="#theme">
  </template>
</my-element>

Then we can combine the two concepts, and import a subsheet from an inline style:

<style id="bundle">
  @sheet subsheet {
   // actual style
  }
</style>

<my-element>
  <template shadowrootmode=open>
    <style>
      import subsheet from "#bundle";
    </style>
    <!-- or -->
    <link rel=stylesheet href="#bundle" sheet="subsheet">
  </template>
</my-element>

If people like this direction, we can get the blessing from WHATWG, work on the @sheet and @import extensions here, and work on importing inline styles/scripts separately at whatwg/html.

A note about shadow-DOM/IDs/mime-type: a fragment URL is not shadow-encapsulated (and shouldn't be in this case). You can have a link with a fragment inside shadow DOM and it would be change the document's URL if clicked. And the mime-type of the fragments here is HTML, so everything checks out in that regard.

@jyasskin
Copy link
Member

+1 to @noamr's synthesis overall, and good point that URL fragments in HTML pages naturally point to elements in the outermost light DOM.

If I'm understanding the needs of server-side rendering correctly, we're also going to need some way to refer to elements inside shadow DOM, as the natural structure for SSR will sometimes look like

<!-- Use a component that uses a shared component -->
<template shadowrootmode="open">
  <!-- Here comes a component whose style might need to be shared later. -->
  <style id="shared-component-style-outside">@sheet actual-content {...}</style>
  <template shadowrootmode="open">
    <style id="shared-component-style-inside">...</style>
    <!-- Shared component shadow DOM -->
  </template>
</template>
<!-- Here comes another copy of the component that needs shared style. -->
<!-- DON'T re-emit the style -->
<template shadowrootmode="open">
  <!-- Doesn't find the style because it's in 2 layers of shadow DOM -->
  <link rel=stylesheet href="#shared-component-style-inside">
  <!-- Still doesn't find the style because it's in 1 layer of shadow DOM -->
  <link rel=stylesheet href="#shared-component-style-outside" sheet=actual-content>
  <!-- Shared component shadow DOM -->
</template>

This is not a CSS problem to solve: HTML as a whole needs a way to explicitly name IDs inside shadow DOM. It's related to WICG/webcomponents#66 (comment) and https://github.com/WICG/webcomponents/blob/gh-pages/proposals/reference-target-explainer.md.

@KurtCattiSchmidt
Copy link
Author

Here, @sheet with fragment URLs solves the problem of "partially importing from a sheet".

For solving the declarative shadow DOM problem ("importing from inline"), I believe <link rel="stylesheet" href="#style-element"> would go a long way, without complicating @sheet. I'm looking forward to @KurtCattiSchmidt opening a dedicated issue for href="#style-element".

Heads-up that I have posted a WHATWG issue for this here: whatwg/html#11019

@KurtCattiSchmidt
Copy link
Author

@bramus

Yes, in the longer thread above I think I am responding to what I think is @KurtCattiSchmidt's interpretation of how to potentially address that same F2F discussion/decision:

The CSSWG decided at the F2F last week to not go with URL fragments for binding to @sheet identifiers, so we're now looking into adding an attribute to tags to specify which sheet is being imported as well as adding an optional identifier to @import for similar functionality there (e.g. @import sheet1 from "style.css").

Are you and @KurtCattiSchmidt talking about the same thing? I am assuming @KurtCattiSchmidt meant that <link rel="stylesheet" href="#reference-straight-to-an-atsheet-inside-a-style-element" /> was out? So the explainer was updated to consider <link rel="stylesheet" href="#sheet" sheet="foo" />? With a potential new proposal to flesh out the natural consequences of thereby enabling <link rel="stylesheet" href="#sheet" />?

Please correct my misunderstanding.

Yes, this is exactly the new proposal - I don't see any misunderstanding.

We do need to figure out the specifics of "reference vs copy" of the stylesheets in all of these scenarios.

I can see lots of value in the SVG <use> behavior that you suggested, but we might not be able to adjust the existing behavior of CSS Modules without breaking existing usage. But perhaps we can make it work with some slight modifications to the syntax to handle both cases.

I'll think about this and may propose some new updates. At the very least, there should be a table that indicates reference vs copy of stylesheets for each method of sharing stylesheets, as that will clarify a lot of the current discussion.

@KurtCattiSchmidt
Copy link
Author

Also, in case this is also a source of confusion, for consistency I have been using the same identifier names as the original and updated explainer:

<style id="sheet"> @sheet foo { div { color: red; } } </style>

Where "#sheet" is not a URL fragment identifier to a sheet, but the id of the style element that contains a sheet. "#foo" is the identifier of the sheet inside the style element.

I see people calling any other CSS rules in the #sheet id style element that are not inside a @sheet block "rules outside of @sheets", so I am too. So <link rel="stylesheet" href="#sheet" /> in explainer terminology perhaps confusingly doesn't refer to @sheets at all, but rules outside of @sheets.

I can see how this is confusing - I will update this, thank you @robglidden!

@robglidden
Copy link

@KurtCattiSchmidt

I can see lots of value in the SVG <use> behavior that you suggested, but we might not be able to adjust the existing behavior of CSS Modules without breaking existing usage. But perhaps we can make it work with some slight modifications to the syntax to handle both cases.

I'll think about this and may propose some new updates. At the very least, there should be a table that indicates reference vs copy of stylesheets for each method of sharing stylesheets, as that will clarify a lot of the current discussion.

Yes, a table would be clarifying.

And it would be a no-go to break existing behavior or usage of the specific case of CSS Modules (import styles from './styles.css' with {type: "css"}) or modules in general (import {foo} from './bar.js'). No change needed or suggested there.

But these existing module usages (like link rel) to date only allow specifiers (i.e. references) to network resources (i.e. files): relative, absolute, and bare.

They do not currently allow or even contemplate references to DOM elements (loosely a term for inline module scripts or in-document element references).

So no existing usage would necessarily be broken by adding a new specifier/reference type for in-document references to complement #11019 fragment references <link rel="stylesheet" href="#inline_styles">.

But it could help unblock and complete the assessment of this situation (and also open the door to a lot of new possibilities of other data types and bundling replacements).

I think this could be an indirect implication of @noamr mention of allowing import {something} from "#bundle";, which of course now just produces:

Uncaught TypeError: Failed to resolve module specifier "#bundle". 
Relative references must start with either "/", "./", or "../".

It would be helpful to know if there is some past consideration that points away from this reasoning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Wednesday morning
Development

No branches or pull requests