CSS nesting
The styles of one component are often spread over several rules: .card, .card h3, .card:hover. Each time .card has to be repeated. Nesting lets you write rules for descendants right inside the parent's rule. This used to require preprocessors like Sass, but since 2023 nesting works in plain CSS in all modern browsers.
A rule inside a rule
A nested rule is written inside the curly braces of the parent one. It applies to the parent's descendants — as if the selectors were separated by a space:
<style>
.card {
padding: 12px;
background: lavender;
h3 { margin: 0 0 4px; color: rebeccapurple; }
p { margin: 0; }
}
</style>
<div class="card">
<h3>Anna</h3>
<p>Front-end developer</p>
</div>The h3 inside .card is the same as the usual selector .card h3.
The & symbol
The & symbol means "the parent selector itself". It is needed when a selector must be glued to the parent without a space — for pseudo-classes and extra classes:
<style>
.btn {
padding: 8px 16px;
border: none;
background: steelblue;
color: white;
&:hover { background: crimson; }
&.big { font-size: 20px; }
}
</style>
<button class="btn">Normal</button>
<button class="btn big">Big</button>&:hover turns into .btn:hover, and &.big into .btn.big.
Nested media queries
@media and @container can be nested too. Then all the styles of an element — normal and responsive — live in one place:
<style>
.title {
font-size: 18px;
color: seagreen;
@media (min-width: 500px) {
font-size: 28px;
}
}
</style>
<p class="title">In a wide window the font is bigger</p>Inside a nested media query the properties are written directly, without repeating the selector. Narrow the browser window until the example is under 500 pixels wide — the heading gets smaller.
& at the end
& can stand not only at the start. The form .dark & means "this element inside .dark" — handy for describing a variant of a component in other surroundings:
<style>
.label {
padding: 4px 8px;
background: gold;
.dark & { background: black; color: gold; }
}
.dark { padding: 8px; background: dimgray; }
</style>
<span class="label">Light background</span>
<div class="dark"><span class="label">Dark background</span></div>Do not overdo it
Each nesting level makes the selector longer and raises its specificity — its strength in the cascade. Deep chains like .page .main .card .title span are hard to override and easy to break. A good rule is no more than two or three levels. To limit styles to a component without raising specificity, use the @scope rule — see the lesson "Style scope: @scope".
Written inside .card | What you get |
|---|---|
p | .card p |
&:hover | .card:hover |
&.active | .card.active |
& + & | .card + .card |
.dark & | .dark .card |
Common mistake
A pseudo-class without & turns into a descendant selector. :hover inside .link means .link :hover — "any descendant under the cursor", not the link itself:
<style>
.link {
color: steelblue;
:hover { color: crimson; }
}
.ok {
color: steelblue;
&:hover { color: crimson; }
}
</style>
<p><a class="link" href="#">Without &: does not turn red</a></p>
<p><a class="ok" href="#">With &: turns red on hover</a></p>For pseudo-classes and pseudo-elements always write & right next to them: &:hover, &::before.