T

When you first hear about css @scope, you think: so what does it actually scope? And the answer is that it scopes where the css applies.

You also ask yourself, why do we need that? What is the difference between @scope (.parent) { .child { … } } and .parent .child { … } or .parent { & .child { … } }? And the answer is: not much difference there, except a few nuances:

  • you can add a lower boundary, like so: @scope (<scope start selector>) to (<scope end selector>) { … } (the end element and its subtree are excluded)
  • specificity of scoped selectors ends up to be as writen

What @scope doesn’t do:

  • it does affect cascade due to proximity based conflict resolution, but it doesn’t encapsulate styles the way Shadow DOM does
  • it doesn’t affect property inheritance (inherited values can pass into and out of the scoped subtree)

@scope adds a very useful element to the cascade, which is proximity based conflict resolution—another layer of cascade resolution.

Current cascade order: cascade layer → specificity → scoping proximity → order of appearance (source order).

Initially we had only specificity → source order, then cascade layers were introduced as a way to define cascade at higher level of abstraction.

Scoping proximity in the cascade: when competing declarations come from different scopes, the one whose scope root is closer to the element wins, even if source order would otherwise decide.

There is also “inline” @scope, which I find really cool—until now there was a little reason to enclose <style> into a particular element; now you can do this:

<parent>
  <style>
    @scope { /* root is the <style>'s enclosing parent */ }
  </style>
</parent>