Problems solved by CSS @scope

CSS @scope, if fully implemented, could be an absolute game-changer in the coming years.

It could:

  • mark the end of fifteen years of CSS scope hacks
  • give a native way to unambiguously define which CSS belongs to a piece of interface
  • allow to safely delete parts of CSS code

I won't focus on how CSS @scope works, rather I'll focus on what problems it solves, as described in CSS Scope Proposal & Explainer.

The global scope problem

CSS Selectors are global, matching against the entire DOM.

So it's really really hard to avoid conflicts.

To solve this, we use hacks to isolate selectors via:

  • naming conventions (BEM or Block-Element-Modifier)
    • each Block component must have a unique name
    • any internal Element or Modifier will be scoped to its Block
  • or JS tooling (CSS Modules, Styled Components, Vue Scoped Styles)
    • to generate unique block names
    • and append them to elements automatically

The proximity problem

Problems arise with nested styles:

.foo i { color: fuchsia; }
.bar i { color: blue; }

<div class="bar">

    <i>Blue</i>

    <div class="foo">
        <i>Also blue</i>
    </div>

</div>

Both .foo i and .bar i apply to the 2nd <i> element:

  • in the current CSS cascade algorithm
    • when two rules of equal specificity apply to the same element
    • the later a declaration appears
    • the more weight it is given
  • so .bar i will always take precedence

Rules are not weighted by proximity to the element being styled.

And this makes it hard to build modular components you can nest wherever you want.

The ownership problem

Problems arise with modular components, e.g.:

  • a modal component is only useful when we put other content inside
  • however, the modal element doesn't know what that content will be
  • so the scope of the modal component styles should stop where the content begins

This is sometimes referred to as donut scoping, a term coined by Nicole Sullivan:

When components have a hole in the middle (or a slot) for other content to go inside.

These components are hard to style because CSS selectors are limited in what scopes they can express.

BEM attempts to solve this by explicitly specifying the idea of ownership or belonging in CSS:

/* Any title inside the component tree. */
.component .title { /* too broad */ }

/* Only a title that is a direct child of the component. */
.component > .title { /* break if we add a wrapping element around the child */ }

/* Just the title of the component. */
.component__title { /* explicit belonging */ }

Further reading

Avant Database Relationships in Django Après Any software project has a complexity budget

Tag Kemar Joint