One Thing @scope Can Do is Reduce Concerns About Source Order
One Thing @scope Can Do is Reduce Concerns About Source Order êŽë š
There is an already-classic @scope
demo about theme colors. Letâs recap that and then Iâll show how it relates to any situation with modifier classes. (The @scope
rule is a newish feature in CSS that is everywhere-but-Firefox, but is in Interop 2025, so shouldnât be too long to be decently usable.)
There are lots of different ways to implement color themes, but imagine a way where you do it with class names. I think itâs a valid way to do it, rather than, say, only responding to system preferences, because the classes might give you some on-page control. So you apply a theme at the top level. Then perhaps you have some elements that have other themes. Perhaps your site footer is always dark.
<body class="theme-light">
<main>
...
</main>
<footer class="site-footer theme-dark">
©2025 <a href="/">Frontend Masters</a>
</footer>
</body>
You set up those classes with colors, including other elements that need colors depending on that theme.
.theme-dark {
background: black;
color: white;
a {
color: #90caf9;
}
}
.theme-light {
background: white;
color: black;
a {
color: #1976d2;
}
}
There is already a problem with the HTML and CSS above.
The <a>
in the footer will have the color of the light theme, not the dark theme. This is that classic @scope
demo youâre likely to see a lot (sorry). This is because of source order. The selector .theme-light a
has the exact same specificity as .theme-dark a
but the light theme comes after so it âwinsâ.
One change to the above CSS will fix this:
@scope (.theme-dark) {
background: black;
color: white;
a {
color: #90caf9;
}
}
@scope (.theme-light) {
background: white;
color: black;
a {
color: #1976d2;
}
}
This is referred to as proximity. Itâs like a new part of the cascade (Bramus has a nice diagram here). Above, because the specificity is the same in both cases, the closer-in-the-DOM proximity âwinsâ. And closer meaning âfewest generational or sibling-element hopsâ. Like:

So, appropriately, the link styling nested under @scope (.theme-dark)
wins because the specificity is the same but the proximity of the theme-dark
class is closer.
What I like about this is that now the source order for those themes doesnât matter. Thatâs nice as sometimes thatâs hard to control. A good bundler should maintain source order after building, but perhaps these âvariation classesâ are in different files and the way they get built and loaded isnât entirely predictable. Perhaps some lazy loading gets involved or the built files are purposefully spit or who-knows-what. Iâve seen too many âitâs fine on dev but broken on prodâ bugs for one lifetime.
Color themes was just an excuse to look at variation classes.
Hereâs another example:
.card-big {
padding: 2rem;
}
.card {
padding: 1rem;
}
Without even looking at HTML, you might consider this a âmistakeâ because, probably, card-big
is a variation class of .card
, except the thing that should be an override (the padding
) wonât actually be overridden because of source order and equal specificity. Iâd guess we all have some muscle memory for just ordering variation classes properly so this isnât a problem, but itâs not ideal to me that we have to remember that, and that build tools and loading strategies might interfere anyway.
Hereâs some real-world-ish CSS I was playing with where I could use @scope
to put my variation class first without worry:
@scope (.card-big) {
:scope {
grid-column: span 2;
display: flex;
img {
width: 50%;
height: 100%;
}
}
}
.card {
img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
}
Now if Iâve got two cardsâŠ
<div class="card">
...
</div>
<div class="card card-big">
...
</div>
I can rest easy knowing the .card-big
styles will apply and appropriately override because of the proximity of the class to the things I want to style (including itself!)
