Native CSS Nesting vs Sass Nesting: What Changed and What to Use

The short answer
Native CSS nesting and Sass nesting look almost identical, but they are not the same feature. Sass nesting is a build-time convenience: your .scss compiles to flat CSS, so it runs everywhere and the & symbol does literal string gluing. Native CSS nesting is a real browser feature: the & is a live selector reference (it behaves like :is()), there is no compile step, and it needs a reasonably modern browser to work.
For most new projects in 2026, native CSS nesting is enough on its own. You reach for Sass nesting when you need BEM-style &__element concatenation, when you must support older browsers without a build step, or when nesting is just one reason among many that you already use Sass (variables, mixins, @each loops, partials).
Here is the same component written both ways.
// Sass (SCSS)
.card {
padding: 1rem;
&__title { // compiles to .card__title
font-weight: 700;
}
&:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
}
/* Native CSS */
.card {
padding: 1rem;
& .title { /* compiles to nothing — this IS the output */
font-weight: 700;
}
&:hover {
box-shadow: 0 2px 8px rgb(0 0 0 / 0.15);
}
}
Notice the difference already: Sass can build .card__title from &__title, but native CSS cannot. That single limitation drives most real-world decisions.
The differences that actually matter
| Behavior | Native CSS nesting | Sass nesting |
|---|---|---|
| Runs in the browser | Yes, no build step | No — compiles to flat CSS first |
&__element BEM concatenation |
Not supported | Supported |
What & means |
Live reference, acts like :is() |
Literal text substitution |
Specificity of & |
Highest in the parent list | Each selector keeps its own |
Nest @media / container queries |
Yes | Yes |
| Browser support needed | Modern browsers only | None — output is plain CSS |
| Variables, mixins, loops | No | Yes |
1. BEM concatenation only works in Sass
This is the biggest practical gap. In Sass, & is glued to whatever follows it as plain text:
.card {
&__title { color: navy; } // -> .card__title
&--featured { border: 2px solid gold; } // -> .card--featured
}
Native CSS cannot do this. In the browser, & is a selector, not a string, so &__title does not produce .card__title — it is read as the parent followed by a type selector named __title, which matches nothing useful. If your codebase leans on BEM naming, native nesting will not replace that part of Sass. You either keep Sass for the concatenation or write the full class names out:
.card { padding: 1rem; }
.card__title { color: navy; } /* just write it flat */
2. & and specificity behave differently
In Sass, & is substituted before the CSS ever reaches the browser, so each generated selector carries its own specificity. In native CSS, & matches like the :is() pseudo-class, which takes the highest specificity in the parent selector list. That changes the math when a rule has several parent selectors:
#app, .menu {
& a { color: teal; }
}
/* & a behaves like :is(#app, .menu) a
-> specificity is driven by #app (an ID) for BOTH */
The equivalent Sass would emit #app a, .menu a as two separate selectors, so .menu a keeps its low class-level specificity. If you migrate Sass nesting to native CSS and mix IDs and classes in one parent list, some rules can suddenly win or lose the cascade. When specificity surprises you, our guide to CSS specificity walks through exactly how the browser scores these.
3. Native nesting has no variables, loops, or mixins
Nesting is one feature. Sass is a whole language. Native CSS nesting gives you the visual grouping and the &, but it does not give you @mixin, @include, @function, @each, maps, or math. CSS custom properties cover a lot of what people used Sass variables for, but they do not replace design-token loops or a @mixin that stamps out a media-query breakpoint. If nesting is the only Sass feature you use, native CSS can retire your preprocessor. If you use the rest, keep Sass — see Sass vs SCSS for how the two syntaxes fit into that bigger toolkit.
4. Both can nest media and container queries
One of the nicest wins of nesting — in either flavor — is keeping a component's responsive rules next to the component instead of scattered at the bottom of the file. Both syntaxes support it, and they read almost identically:
/* Native CSS */
.card {
display: grid;
gap: 1rem;
@media (min-width: 768px) {
grid-template-columns: 1fr 2fr;
}
@container (min-width: 400px) {
gap: 2rem;
}
}
// Sass (SCSS) — same shape
.card {
display: grid;
gap: 1rem;
@media (min-width: 768px) {
grid-template-columns: 1fr 2fr;
}
}
Native CSS also lets you nest container queries this way, which pairs well with modern component-based responsive design. If you are new to breakpoints, our guide to CSS media queries covers the syntax in depth.
Migrating Sass nesting to native CSS
If you want to drop the build step, most Sass nesting ports over cleanly. The two things that break are BEM concatenation and mixed-specificity parent lists. A safe checklist:
- Find every
&__and&--. These are the concatenation cases native CSS cannot reproduce. Expand them into full class names (.card__title) or keep those files in Sass. - Prefix nested selectors with
&or a combinator. Writing& .titlerather than a bare.titlekeeps intent obvious and avoids the oldest parser edge cases. - Check parent selector lists that mix IDs and classes. Because native
&acts like:is(), split#app, .menu { & a {...} }into separate rules if the shared specificity would change which style wins. - Keep
@mediaand@include-free nesting as-is. Plain grouping,&:hover,&:focus, and nested media queries all translate one-to-one.
Anything that used @mixin, @function, @each, or Sass math is not a nesting concern — that is the rest of the language, and native CSS has no equivalent.
Browser support in 2026
Native CSS nesting is Baseline widely available. The & nesting syntax shipped across the board in 2023 (Chrome 112, Safari 16.5, Firefox 117), and the more forgiving "relaxed" syntax — which lets a nested rule start with a bare element selector like p without a leading & — landed shortly after (Chrome 120, Safari 17.2). By 2026 both are safe in every evergreen browser.
The practical caveat is old browsers. If your analytics still show meaningful traffic from browsers older than late 2023, native nesting will silently fail for those users. Two safe paths:
- Keep the
&prefix. Writing& .titleinstead of a bare.titleis a touch more explicit and sidesteps the earliest parsing quirks. It costs nothing and reads clearly. - Downcompile with PostCSS. The
postcss-nestingplugin flattens native nesting into plain CSS at build time, so you write modern syntax and ship output that works everywhere — the same trick Sass has always used. Our preprocessors vs PostCSS comparison covers where PostCSS fits.
Rules that apply to both
Whichever you choose, the same nesting mistakes bite you.
- Do not nest more than three levels deep. Deep nesting produces long, brittle, over-specific selectors that are hard to override. The old Sass "inception rule" (never go more than four levels in) is still good advice for native CSS.
- Nesting mirrors your HTML structure, which is fragile. A selector like
.nav .list .item .linkbreaks the moment someone reorders the markup. Prefer a single meaningful class per component. - Grouping is not free specificity. Nesting
.titleinside.cardproduces.card .title— a descendant combinator, not a scoped variable. It still leaks to any.titleanywhere inside the card.
Which should you use?
A quick decision guide:
- New project, modern browsers, no BEM: use native CSS nesting. One less dependency, no build step, and the browser does the work.
- You use BEM
&__elementnaming: stay with Sass, or accept writing class names out in full. - You already use Sass for variables, mixins, and partials: keep nesting in Sass so your whole stylesheet speaks one language. The complete guide to Sass shows how nesting sits alongside those features.
- You need modern syntax but old-browser output: write native nesting and downcompile with
postcss-nesting.
The honest summary: native CSS nesting has closed most of the gap, and for a large share of projects it makes preprocessor nesting optional. But "nesting" was never the main reason to adopt Sass. If you only ever nested, CSS has caught up. If you use the rest of the language, nesting natively or in Sass is a style choice, not a migration.