Nesting keeps component styles together and removes the main reason many projects used Sass.
CSS supports nesting natively in every current browser. Inside a rule you can write further rules that apply relative to the parent selector.
.card {
padding: 1rem;
& h2 { margin: 0; } /* .card h2 */
&:hover { background: #f8f8f8; } /* .card:hover */
.dark & { background: #222; } /* .dark .card */
}& stands for the parent selector. A nested selector without & is treated as a descendant, so h2 { } inside .card means .card h2 (the & is optional there). Use & explicitly when attaching pseudo-classes (&:hover) or when the parent goes in the middle or end (.dark &).
Media queries, container queries, @supports and @layer can nest inside a rule, applying to the current selector, which keeps responsive tweaks next to the styles they modify.
Differences from Sass to know:
- No string concatenation:
&__title(BEM-style suffixes) does not work. &behaves like:is(parent), so specificity follows:is()rules: a parent list such as#a, .bis treated as if it were the id everywhere.- Declarations written after nested rules are allowed; they're treated as if in their original order.
Don't nest deeply. Each level adds specificity and couples styles to markup structure; one or two levels is plenty.
Example
.card {
padding: 1rem;
border-radius: 12px;
& h2 { margin-block: 0 0.5rem; } /* .card h2 */
& > img { width: 100%; } /* .card > img */
&:hover { box-shadow: 0 4px 16px rgb(0 0 0 / 10%); }
&.featured { border: 2px solid gold; } /* .card.featured */
[data-theme="dark"] & { background: #1f2937; } /* ancestor context */
@media (width >= 48rem) {
padding: 2rem; /* .card at wide widths */
}
}Remember
- & is the parent selector; nested selectors default to descendants
- Media and container queries can nest inside rules
- No Sass-style &__suffix concatenation
- Keep nesting to one or two levels
Watch out for
- Porting Sass that relies on &-suffix concatenation and getting silently broken selectors.