Early Days for CSS Scoping

Avatar of Chris Coyier
Chris Coyier on (Updated on )

There is a working draft spec for CSS scoping now. Other than a weird period where <style scoped> shipped and then was subsequently removed from the spec (and browsers), this is the furthest a scoping proposal has gotten (the Level 1 spec never got anywhere).

This one comes from Miriam Suzanne.

The basics:

<div class="media">
  <img alt="Proper alt." src="...">
  <div class="content">
    <p>...</p>
  </div>
</div>

If I’m thinking of this bit of HTML as a “component,” it’s nice to be able to write styles for it that are very explicitly just for it. That’s what @scope is for, so…

@scope (.media) {
  :scope {
    display: grid;
    grid-template-columns: 50px 1fr;
  }
  img {
    filter: grayscale(100%);
    border-radius: 50%;
  }
  .content { ... }
}

What I like about that is:

  1. This bit of CSS is very explicitly for this media component. It reads like that and can be maintained like that.
  2. I didn’t have to come up with a name and class for the <img>. I’m applying styling there without it “leaking out” to other images.

But wait, isn’t this just like prepending selectors with the parent class?

It kind of is… like we could also write:

.media {
}
.media img {
}
.media .content {
}

And now we’ve scoped things internal to the media component. That’s rather repetitive, but with native CSS nesting on the way, it’s just this:

.media {
  & img {
  }
  & .content {
  }
}

So yes, I’d say nesting takes care of some basic types of scoping, but there are some things that are very unique to this new scope proposal.

One unique feature is “donut scope” meaning I stop the scoping where I want to. Maybe I want my scoping to stop at a particular class:

@scope (.media) to (.content) {
  p { }
}

Now I can write styles that won’t mess with areas that I don’t want them to mess with. Perhaps:

<div class="media">
  <img alt="Proper alt." src="...">
  <p>This is stylable in scope.</p>
  <div class="content">
    <p>This is NOT styleable in scope.</p>
  </div>
</div>

But that’s not the only unique problem this new spec solves. I think the “nearest ancestor” situation that Miriam lays out is perhaps the most interesting thing. I’ll send you over to the blog post to read about that — it’s pretty wild that we don’t have a good tool for that yet.

There is a lot to wrap your mind around here, especially as you think of more complex situations, like multiple overlapping scopes and how the nesting syntax might interplay with scoping. Fortunately, Miriam is blogging these things very clearly.