webc icon indicating copy to clipboard operation
webc copied to clipboard

CSS: Support scoping inner elements of a webc file

Open bglw opened this issue 2 years ago • 5 comments

Assumption about the current state:

If I have the file:

<div>
  <h1>Example</h1>
  <p>Content</p>
</div>

<style webc:scoped>
:host h1 {
	color: aliceblue;
}
:host p {
	color: blanchedalmond;
}
</style>

After compilation I would currently see:

{
	html: "<div class=\"wcl2xedjk\"><h1>Example</h1><p>Content</p></div>",
	css: [".wcl2xedjk h1{color:aliceblue}.wcl2xedjk p{color:blanchedalmond}"],
}

Main concern:

For components that wrap another component, this isn't scoped enough to prevent style leakage. For example if our component above had a child component within it, and that child component also contained an h1 element, then .wcl2xedjk h1 would apply and turn it aliceblue.

Desired behaviour:

In Svelte's CSS scoping, I can write the following:

<div>
  <h1>Example</h1>
  <p>Content</p>
</div>

<style>
h1 {
	color: aliceblue;
}
p {
	color: blanchedalmond;
}
</style>

Which would provide me something along the psuedo-lines of

{
	html: "<div><h1 class=\"kziuyb\">Example</h1><p class=\"wgrhia\">Content</p></div>",
	css: ["h1.kziuyb{color:aliceblue}p.wgrhia{color:blanchedalmond}"],
}

Where the styles are scoped directly to the elements they applied to.

Implementation:

In (my) ideal world this would happen automatically when webc:scoped is applied. Alternatively to keep it opt-in it one could utilize something like a :host pseudo-class wrapping styles:

<style webc:scoped>
:host(h1) {
	color: aliceblue;
}
:host(p) {
	color: blanchedalmond;
}
</style>

Ideally slightly more complex selectors would also be handled, so h1 + p:first-child could become h1.qwerty + p.asdfgh:first-child

bglw avatar Sep 09 '22 21:09 bglw

Reclassifying this one as a bug

zachleat avatar Sep 20 '22 21:09 zachleat

I’m waffling back and forth here because I do kinda think this is okay and as a better short term solution I’d like to ship an example of how to override the webc:scoped behavior with any arbitrary css scoping library e.g. css modules maybe? Any opinions on what a good next-level library for this might be?

zachleat avatar Nov 01 '22 13:11 zachleat

Makes sense. I don't know of any css scoping libraries myself, but that would be a cool thing to find

bglw avatar Nov 01 '22 18:11 bglw

lightningcss might be a good library to show how to use css modules with. If not, postcss-modules is another option (i believe this is what vue uses under-the-hood as well). both of these solve the inner-element scoping problem and they give you a json mapping of the original vs transformed class name, which could be substituted against webc's own internal mapping.

also worth mentioning that native scoping is coming and it might be good to start thinking about it. for example, webc could manage a unique hash to pass inside @scope.

mayank99 avatar Dec 16 '22 01:12 mayank99

This is still important as long as scoped prefixing occurs before transforming... currently, the CSS being fed to a preprocessor is not what the developer wrote, but the result of applying the prefix transform. This creates unintended side effects.

ghost avatar Jun 01 '23 14:06 ghost