Convert CSS Modules to scoped styles#38
Merged
Merged
Conversation
drwpow
commented
Mar 30, 2021
| } | ||
|
|
||
| /** PostCSS Scope plugin */ | ||
| export default function astroScopedStyles(options: AstroScopedOptions): Plugin { |
Member
Author
There was a problem hiding this comment.
This could maybe be its own PostCSS plugin eventually? But local for now.
drwpow
commented
Mar 30, 2021
| '.class *': `.class${className} ${className}`, | ||
| '.class>*': `.class${className}>${className}`, | ||
| '.class :global(*)': `.class${className} *`, | ||
| '.class:not(.is-active)': `.class${className}:not(.is-active)`, // Note: the :not() selector can NOT contain multiple classes, so this is correct; if this causes issues for some people then it‘s worth a discussion |
Member
Author
There was a problem hiding this comment.
The PostCSS plugin code may be a little hard to follow, so treat these tests as the proof. Please suggest more tests if you see any complicated stuff missing!
FredKSchott
approved these changes
Mar 30, 2021
Member
FredKSchott
left a comment
There was a problem hiding this comment.
LGTM! Loved the loom.
Your PR comment around performance is good to keep in mind, but that sounds like a nightmare and your note on the Svelte teams difficulty means I'd definitely prefer the plan outlined here, at least for now.
| elementNodes.push(node); | ||
| // 3. add scoped HTML classes | ||
| if (NEVER_SCOPED_TAGS.has(node.name)) return; // only continue if this is NOT a <script> tag, etc. | ||
| // Note: currently we _do_ scope web components/custom elements. This seems correct? |
Member
There was a problem hiding this comment.
I think that's right? Could be worth confirming as we start onboarding people
| attr.value[k].data += ' ' + scopedClass; | ||
| } else if (attr.value[k].type === 'MustacheTag' && attr.value[k]) { | ||
| // MustacheTag | ||
| attr.value[k].content = `(${attr.value[k].content}) + ' ${scopedClass}'`; |
jsparkdev
added a commit
that referenced
this pull request
May 12, 2026
* fix: use named HTML entities for attribute escaping Update the attribute escaping logic to use named entities (& and ") instead of numeric ones (& and "). This improves the readability of the rendered HTML and follows common conventions for character references. * changeset * update changeset
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
Also as mentioned in the video, we kinda have to use PostCSS anyway because that’s still where a lot of important style libraries are maintained, like autoprefixer. And since we are using PostCSS, it does a ton of lifting that Svelte has to implement manually. Given the choice between tying yourself to Svelte’s parser, vs PostCSS, the latter seems safer.
Reasoning
divs within an.astrocomponent)class="nav"on an element, that’s now preserved withclass="nav astro-gu2vWp"rather than obfuscated toclass="nav-gu2vWp"beyond your control)Notes
This version matches Svelte‘s implementation with one major difference: Svelte only adds scoped HTML classes where necessary, and Astro adds scoped HTML classes to all elements within a component.
For example, say you had an
<h1>tag in a Svelte component. Svelte would leave it as<h1>until you wrote a style rule targeting it, then it would add the<h1 class="svelte-hxgzt2p">class. Astro, regardless, adds a<h1 class="astro-hxgzt2p">scoped class whether you wrote styles for it or not.The advantage in Astro’s favor is that we can process this much more efficiently than Svelte, as we can parallelize adding HTML classes as the styles are being built (Svelte, conversely, has to build styles first, then query what‘s used over-and-over again, thereby slowing down the whole compilation). Astro‘s method is also less error-prone, as Svelte has to rely on complicated lookups within your component to tell if you‘re really using it or not (and they’ve had to fix many bugs for complex selectors like
.menu:focus > ul > li + lias they‘re recreating DOM selectors 🙈). But the advantage in Svelte‘s favor (assuming it’s correct) is that the HTML payload may be smaller with a few less classes. Still, gzip cuts down on this by quite a lot (it‘s the same class over and over again per-component), so gut tells me that our approach will be faster and more reliable for more users. I’d only want to look on removing unused CSS classes as part of a larger effort, and only if it has a big payoff.Testing
Docs