Lesson 14 of 37
Native CSS Nesting
Writing nested selectors directly in CSS — no Sass, no preprocessor — with the `&` parent reference, nested at-rules, and a few honest gotchas about what native nesting won't do.
Nesting selectors inside each other was the single most popular reason to adopt a CSS preprocessor for a decade. Being able to write a component's base styles, its hover state, its focus state, and its media queries in one block instead of five was worth a whole Sass or LESS build step for most teams.
Native CSS now does it directly. No preprocessor, no build step,
no .scss extension — the browser parses nested rules the same
way it parses any other CSS.
The base syntax, with and without &
Two shapes to get comfortable with:
/* Plain descendant nesting — `&` is optional. */
.card {
background: white;
h2 {
font-size: 1.25rem;
}
p {
line-height: 1.6;
}
}The h2 and p rules apply to descendants of .card. You can
write the parent reference explicitly if you want (& h2 { ... })
but it's not required for the descendant case.
The parent reference is required for compound selectors that attach to the parent itself:
.button {
background: var(--brand);
&:hover {
background: var(--brand-dark);
}
&.primary {
font-weight: 600;
}
&[disabled] {
opacity: 0.5;
}
}&:hover means .button:hover, not .button :hover. The space-vs-
no-space is load-bearing; & lets you make the distinction clearly.
The reversed form
You can put & in any position, not just at the start. The common
use is "I want this component to behave differently inside a
specific ancestor context":
.icon {
color: currentColor;
/* Inside a dark-themed wrapper, show the icon brighter. */
.dark & {
color: var(--brand-light);
}
}That compiles to the equivalent of .dark .icon. The & is in the
right place for a reader to see "this component, inside a dark
context."
Nested at-rules
The quietly useful feature: @media, @container, @supports,
and others nest directly, and the parent selector applies inside
the at-rule's body:
.card {
display: block;
@container (min-width: 500px) {
display: flex;
}
@media (prefers-reduced-motion: no-preference) {
transition: transform 0.2s ease;
}
}The media and container queries sit next to the rule they modify, not somewhere else in the file. For a component whose responsive behaviour is a small tweak on a base rule, this is the shape most worth adopting.
The specificity gotcha worth knowing
Native CSS nesting isn't textual substitution the way Sass is. When
the browser evaluates a nested selector, it wraps the parent
selector list in :is(...). That has one specific consequence:
.a, h1 {
& span {
color: red;
}
}The nested & span has the specificity of :is(.a, h1) span,
which is calculated using the most-specific selector in the
parent list — the class. So the effective specificity of & span
here is one class plus one type selector. If h1 span were
written alone, it would have the specificity of two type
selectors, which is lower.
This almost never matters in practice because most nested rules have a single-selector parent. It matters enough to know about if you're porting a Sass stylesheet that mixed classes and type selectors in the same parent list, where Sass would have unrolled each parent individually.
Nesting depth is still a code-smell knob
Just because you can doesn't mean you should. Deeply nested native CSS has the same two problems Sass's deeply nested CSS had:
- Specificity grows with each level.
.card .body .titleis harder to override than.card-title. - Searchability drops. A reader looking for
.titlefinds many hits; a reader looking for the specific.titleinside this card's body finds nothing without opening every file that has a.cardrule.
The useful rule, same as the Sass era: one or two levels of
nesting is a readability win. Three or more starts paying
interest. Nesting a component's states (&:hover, &:focus),
its immediate child elements (& .header, & .body), and its
media / container queries is almost always fine. Nesting a
.grand-child inside a .child inside a .parent is almost
always worse than giving each of those a flat, named class.
Browser support and preprocessor interop
Native nesting is baseline-available — all major browsers support it. You can reach for it the same way you reach for Grid or Flexbox.
If your codebase still uses Sass, the two coexist cleanly: Sass
nesting continues to work and continues to produce textually
unrolled CSS; native nesting works in files you write without
.scss as well. The practical migration path most teams follow
is "stop nesting in Sass for new rules," not "rewrite everything
overnight."
A small gotcha for the Sass crowd: the two differ in the specificity detail described above, and in a handful of edge cases around selector composition. New code written as native should read documentation (MDN's "CSS nesting" page is the clearest reference) rather than assume Sass muscle memory transfers perfectly.
What to remember
&is the parent-reference symbol. Required for compound selectors (&:hover) and reversed-position selectors (.dark &); optional for plain descendants.- At-rules (
@media,@container,@supports) nest directly and keep the parent selector in scope — this is the single biggest readability win. - Specificity gotcha: a parent selector list is wrapped in
:is(), so the specificity of the nested selector reflects the most-specific parent, not each parent individually. Rarely bites with single-selector parents. - Keep nesting shallow — one or two levels. Three or more produces fragile, high-specificity selectors and is the same anti-pattern as deeply-nested Sass.
- Native nesting is baseline-available. Coexists with Sass; new code can be written as native without touching existing Sass files.
Check yourself
4 questions · pass 3/4 to unlock The Cascade and Inheritance
1.In native CSS nesting, what does the
&symbol refer to?2.What's an important gotcha about how a nested selector is actually compiled under native CSS?
3.Can you nest
@mediaand@containerqueries directly inside a rule?4.A naive port of a deeply-nested Sass stylesheet gives you
.a { .b { .c { .d { color: red; } } } }. What's the right habit to form when writing native nesting from scratch?
4 left to answer
Discussion
Sign in to postNo comments yet. Be the first to say something.