Chris’ Corner: Scoping

If I were going to argue against @scope, the new CSS feature, I might say that CSS already has scope. Like, every selector is “scope”. If you say .el, you’re saying “scope this bit of CSS to elements that have the class name of ‘el'”. But then someone might tell you, ok, but what about “donut scope” 🍩? Donut scope is a way for a scope to stop. Keith Grant shows that off in a recent article:

@scope (.card) to (.slot) {
  /* Scoped styles target only inside `.card` but not inside `.slot` */
  :scope {
    padding: 1rem;
    background-color: white;
  }

  .title {
    font-size: 1.2rem;
    font-family: Georgia, serif;
  }
}

Imagine that applied to this HTML:

<div class="card">
  <h3 class="title">Moon lander</h3>
  <div class="slot">
    <!-- scoped styles won’t target anything here! -->
  </div>
</div>

I’m not sure how I feel about that, honestly. Don’t hate it, but also can’t think of a time when I really really wanted that. That might be because it’s never existed so my brain didn’t try to reach for it. But container queries didn’t exist before, either, and I think we all pined for those anyway. Still, it’s a bit of a +1 for @scope because it’s a thing we can’t do any other way.

If I was still arguing against @scope, then I’d say, well, it turns out actually you can replicate donut scope, thanks to another modern CSS feature, :has(), as Bramus blogged:

.from ~ :has(~ .to) {
  outline: 1px solid red;
}

And actually, you don’t even need that.

So I’m afraid I have to rescind the point I gave @scope. Are there any other tricks up its sleeve? It does have one! It’s called proximity. This is just kind of a bummer situation in CSS:

<div class="green">
  <p>I’m green</p>
  <div class="blue">
    <p>I’m blue</p>
  </div>
</div>

If you wrote the CSS like this:

.blue p {
  color: blue;
}
.green p {
  color: green;
}

Then both paragraphs are green. Just because the green selector came second. That’s just how CSS selectors work. Both have the same specificity so the latter one wins. We can fix this with scopes:

@scope (.green) {
  p {
    color: green;
  }
}

@scope (.blue) {
  p {
    color: blue;
  }
}

Now that second paragraph is properly blue because the closer scope wins (and it doesn’t matter what order they are in). This is nice for color theming when you use classes to change the theme “higher up” in the DOM. But it doesn’t save you from increased specificity of other selectors, which are probably a more common “bug”. Still, I’ll say this is worth a +1!

Still, I’m not salivating for @scope. It doesn’t solve any big pain points that I’ve personally had. But maybe it does for you, the web is a big place, so all good.

I’ve said it before, but I think the super old-school idea of wanking a <style scoped> into the DOM anywhere and having those styles scoped to the parent is still a cool idea and actually does solve problems. Coupled with :scope { } it means I don’t even have to think of a name of how to select an element, yet still get the ability to apply pseudo-elements and the like. So inline styles with more abilities. And without having to name anything, there is no possible way for the styles to leak anywhere else. Sure, it’s neat to stop style leaking with a @scope too, but because I have to apply it to a class, I need to make a super obscurely named class like .card_987adf87d (a build tool concern) for it to actually worry-lessly “scope”.

The post Chris’ Corner: Scoping appeared first on CodePen Blog.