Style Donuts: CSS @scope


Tip

This blog post was shown as a talk at Melbourne CSS on 2 October 2024. Join the MelCSS chat on Discord to find details of other upcoming CSS talks in Melbourne.

​

What is this?

The MDN web docs for the @scope rule introduces the @scope feature as follows:

MDN @scope introduction

Let’s break that down…

Limited availability

The @scope at-rule is an experimental CSS feature, Firefox support was added behind a feature flag from version 128 released 2024-07-09.

CSS at-rule

This is applied just like @media rules, wrapped around one or more CSS rulesets.

Targeting elements precisely…

… without writing overly specific selectors. You write simple selectors that are more specific to the content you wish to style, avoiding complex selectors such as :has() and :not().

What does @scope actually do?

It lets you apply regular CSS rulesets within a defined scope.

Given the following DOM tree example from MDN:

body
└─ article.feature
   β”œβ”€ section.article-hero
   β”‚  β”œβ”€ h2
   β”‚  └─ img
   β”‚
   β”œβ”€ section.article-body
   β”‚  β”œβ”€ h3
   β”‚  β”œβ”€ p
   β”‚  β”œβ”€ img
   β”‚  β”œβ”€ p
   β”‚  └─ figure
   β”‚     β”œβ”€ img
   β”‚     └─ figcaption
   β”‚
   └─ footer
      β”œβ”€ p
      └─ img

If you wanted to select the <img> element inside the <section> with a class of article-body, you could do the following:

  • Write a selector like .feature > .article-body > img. However, that has high specificity so is hard to override, and is also tightly coupled to the DOM structure. If your markup structure changes in the future, you might need to rewrite your CSS.
  • Write something less specific like .article-body img. However, that will select all images inside the section.

This is where @scope is useful. It allows you to define a precise scope inside which your selectors are allowed to target elements. For example, you could solve the above problem using a standalone @scope block like the following:

@scope (.article-body) to (figure) {
  img {
    border: 5px solid black;
    background-color: goldenrod;
  }
}

Show me - visually

CSS syntax

@scope (article) to (blockquote) {
  /* CSS rulesets here */
}

Applicable scoped selection

CSS donut scope

🍩 Looking at the shape of the highlighting above, we see a donut which is why we sometimes use the term donut selectors when talking about the @scope rule.

Specificity with @scope

The @scope at-rule doesn’t affect CSS specificity on it’s own, but you can prepend the :scope pseudo-class to scoped selectors which adds 0-1-0 specifity to the selector:

@scope (article) to (blockquote) {
  img {
    /* normal specifity for <img> elements ⟢ 0-0-1 */
  }
  :scope img {
    /* adds 0-1-0 specifity for <img> elements ⟢ 0-1-1 */
  }
}

Note

If you haven’t learned about CSS specicifity, stop right now and take some time to complete the CSS building blocks tutorial at the Mozilla Developers Network (MDN). CSS Specificity is a fundamental CSS skill which is necessary knowledge for all web developers!

What can I use instead of @scope?

The @scope example below:

@scope (article) to (blockquote) {
  img {
    ...
  }
  p {
    ...
  }
}

Can be rewritten without using @scope:

article img:not(blockquote *)
  ...
}
article p:not(blockquote *)
  ...
}

Multiple scopes

You can specify the root and limit selectors as lists, which results in multiple scopes being defined:

@scope (.article-hero, .article-body) to (figure) {
  img {
    border: 5px solid black;
    background-color: goldenrod;
  }
}

@scope in the cascade

Inside of the CSS Cascade, @scope also adds a new criterion: scoping proximity. The step comes after specificity but before order of appearance. @scope in the cascade

Tip

The CSS Cascade is an advanced but fundamental feature of CSS. Follow the Cascade layers lesson over at MDN to complete your understanding of this essential CSS feature.

Selector isolation, not style isolation

The @scope at-rule limits CSS selectors, but it doesn’t prevent styles from being inherited from parent elements.

Thanks!

Questions?

Reminder: I’m available for hire! tyson@clugg.net

I hope you’re ready to use @scope in your project.

Check out my blog for more articles. πŸ™‚

Acknowledgements

This page (and talk) was built with references from the following sources:

  1. MDN contributors. β€œ@scope - CSS: Cascading Style Sheets”, MDN web docs.
  2. Bramus Van Damme. β€œLimit the reach of your selectors with the CSS @scope at-rule”, Chrome for Developers.
  3. Ε ime Vidas. β€œWeekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control”, CSS-Tricks.