Reference guide · html-css-js · Published 2026-08-16 · 3 min read
Native CSS nesting explained
Learn native CSS nesting, the ampersand rules and specificity behavior, and how it compares to preprocessor nesting in Sass.
- ·The basics
- ·The ampersand rule
- ·Specificity behavior
Native CSS nesting lets you nest one rule inside another directly in a stylesheet, without a preprocessor. After years of being a Sass exclusive feature, it became a stable part of CSS and reached baseline widely available support in all major engines. It keeps related selectors together, mirrors the structure of your markup, and removes the need to repeat the parent selector for a whole family of component styles.
The basics
Nesting is simply placing a rule inside another rule so the inner selector is combined with the outer one, in the same way Sass users are already familiar with.
.navigation {
margin: 1rem;
ul {
display: flex;
gap: 0.5rem;
}
a {
color: inherit;
text-decoration: none;
}
}
This compiles to .navigation ul and .navigation a. The nested rules stay grouped with the parent, so you can read the whole component in one block instead of jumping between separate top-level selectors. It works for classes, elements, pseudo-classes, media queries and everything else you would nest.
Because it is a native feature, it runs with no build output, no extra dependency and no risk of a preprocessor mismatch. Where the nesting matches plain CSS, a browser reads it directly.
The ampersand rule
The & symbol refers to the parent selector, and it is the mechanism that keeps nesting general. Consider these two forms:
.card {
& .title { font-weight: 700; } /* .card .title */
&:hover { border-color: blue; } /* .card:hover */
}
Without the ampersand, a nested selector is implicitly combined with the parent using descendant style. The subtle rule that differs from Sass is about relative and compound selectors: a selector that begins with a type selector, such as h2 or div, is treated as descendant and therefore does not need the ampersand, but a compound selector like .active is interpreted as .card.active, not .card .active. When you want the nested selector to combine with the parent rather than descend from it, you prepend it with &, as in & > .media or & + p.
Getting this distinction right is the most common source of surprise when moving nested Sass styles to native CSS without running them through a build.
Specificity behavior
The important difference from Sass is specificity. A nested rule's specificity is computed by merging the specificities of the selectors as they are written, matching the cascade rules of regular CSS. In practice a nested descendant selector has the same specificity as the flattened selector it represents, so .card .title and its nested equivalent resolve identically.
Where preprocessors differ is that Sass concatenated selectors textually, which could produce an inflated specificity for nested compound selectors. Native CSS follows the ordinary rules instead, with the ampersand handled the way a selector list is handled in :is() for specificity purposes. The practical consequence is that you can reason about nested rules with the same specificity intuition you already use, and you can influence the outcome with cascade layers and specificity rather than relying on how deep you nested.
Native nesting composes cleanly with the rest of modern CSS, so you can nest inside custom properties blocks or nest queries inside a component to keep everything in one place. See css specificity for how the cascade settles ties, and cascade layers for ordering nested groups of rules predictably.