[css-scoping] Inclusive vs exclusive lower boundary · Issue #6577 · w3c/csswg-drafts (original) (raw)
https://drafts.csswg.org/css-scoping-2/ describes the possible use of CSS Scoping by component frameworks, with the following example:
@scope ([data-scope='main-component']) to ([data-scope]) {...}
Since the lower boundary is inclusive, this matches the behaviour of the scoped styles in Vue Single-File Components: CSS declared in an SFC's <style>
element apply to all elements of the current component, plus the root element of child components.
But not all userland scoping systems work this way. Svelte has stricter encapsulation: by design, styles declared in one component can't affect a child component at all unless you opt-in to that behaviour with the :global(...)
modifier (demo):
red on yellow
Svelte compiles this to the following CSS:
div.svelte-185puzw p { text-decoration: underline; }
div.svelte-185puzw { background-color: yellow; }
p.svelte-185puzw { color: red; }
The above suggested approach would look like this...
@scope ([data-scope='main-component']) to ([data-scope]) { div p { text-decoration: underline; }
div { background-color: yellow; }
p { color: red; } }
...which would incorrectly apply color: red
to <p data-scope="sub-component">
.
We on the Svelte team would love to be able to use CSS Scoping one day, but we think it's important that a component's styles don't leak into its children unless the author explicitly opts in. If the lower boundary is inclusive, then as far as I can see we would have to do something like this...
@scope ([data-scope='main-component']) to (:not([data-scope='main-component'])) {...}
...and also apply the data-scope="main-component"
attribute to every element. It's not clear that this would be an improvement on the current situation.
Is there a way we might only apply styles until the lower boundary is reached? For example:
@scope ([data-scope='main-component']) until ([data-scope]) {...}
@scope ([data-scope='main-component']) to ([data-scope]) exclusive {...}
More controversially, perhaps the lower boundary should always be exclusive? It's worth noting that you can express the current semantics with an exclusive lower boundary...
@scope ([data-scope='main-component']) to ([data-scope] > *) {...}
...but the reverse isn't true, which to my mind is a strong argument in favour — it gives all authors more expressive power.
edited the final code snippet to remove :not(:scope)
— on a closer reading of the explainer, the lower boundary selector only matches descendants of the upper boundary