You kept Sass for one reason. Native CSS nesting just ended it.
CSS has supported nesting natively since 2023 — pseudo-classes, pseudo-elements, and @media queries nested inside the rules they belong to. No compiler required.

There's a project on every developer's machine that has Sass installed for one reason: &:hover {}. Not @mixin. Not @each. Just the nesting. The variables long since became --custom-properties. The only thing still justifying node_modules/sass is the ability to write child selectors inside parent rules.
CSS added that natively in 2023. It shipped in Chrome 112, Firefox 117, and Safari 16.5 — every major browser released in the last two years. The compiler is not earning its spot anymore.
The classic pattern — component styles scoped to a block, with states and modifiers nested inside:
The output is flat, specificity-controlled CSS. The source is organized by component. That's the trade Sass nesting has always offered — and native CSS now offers the same deal.
Two differences are worth noticing. First: pseudo-classes work exactly as in Sass — &:hover resolves to .card:hover with no extra syntax. Second: descendant selectors require an explicit & followed by a space. & .card__title becomes .card .card__title. This is where native nesting differs from BEM's __/-- convention: in native CSS, & is a selector reference, not a string concatenation operator.
If you're using BEM naming heavily, &__foo becomes & .block__foo. The compiled output is identical; the source is slightly more explicit about what's happening.
Runs right in your browser — poke at it and watch the concept react live.
This is the feature that earns native nesting a permanent spot in how I write stylesheets.
Before, responsive CSS meant jumping between two locations in the same file — the base rule near the top and the @media block somewhere below it, often hundreds of lines away:
With native nesting, the responsive rules live with the component they modify:
Reading an unfamiliar stylesheet gets faster. Instead of tracing a component across multiple @media blocks, all its states are in one place. You see what it looks like at every breakpoint without scrolling past unrelated rules.
Sass could nest @media queries this way too — but only by compiling them back out to separate blocks. Native CSS parses nested @media directly. No output transformation, no source map needed to trace back.
In Sass, & is a string that gets concatenated. &__child produces .card__child. That's why BEM's double-underscore syntax worked so cleanly: the ampersand literally builds the class name character by character.
In native CSS, & is a selector. It means "the selector that contains this rule," and the browser uses it for matching, not text-building. So &__child doesn't produce .card__child — the parser sees it as & (a valid selector ref) followed by __child (an unknown pseudo-class-like token) and ignores the rule silently.
The fix is mechanical: everywhere you have &__element, write & .block__element. Everywhere you have &--modifier, write &.block--modifier (no space, modifier is on the same element). The specificity and the rendered output are identical. The migration is a find-and-replace once you know the pattern to look for.
Chrome 112 (April 2023), Firefox 117 (August 2023), Safari 16.5 (May 2023). That's Baseline 2023: cross-browser in any browser released in the past two years.
For projects that still need to cover older browsers, native nesting degrades safely — unknown nested rules are silently skipped, so the outer rule's styles still apply:
The progressive-enhancement story is the same one container queries, scroll-driven animations, and @layer all tell: declare it, get the enhancement in modern browsers, get the safe fallback in older ones.
Think it clicked? Take the 6-question quiz →
Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.
Open the project with Sass installed. Check whether you use anything beyond nesting: @mixin, @each, @function, @use. If the answer is no — just nesting — you have a straightforward migration. Rename .scss files to .css, change &__child patterns to & .child, remove the build step.
The loop is usually shorter than expected. Two file renames, a find-and-replace, one fewer devDependency. The styles work the same way; the pipeline gets simpler.
What Sass feature are you genuinely still relying on? Because the list gets shorter every year. Nesting was the last one most projects could point to — and it just moved to the platform.
Thanks for reading! Let's stay connected:
- ⭐ GitHub — follow me and star the projects: github.com/parsajiravand
- 💬 Discord — join the frontend best-practices community: discord.gg/d9KRhuAwQ
- 📸 Instagram — frontend best practices, daily: @bestpractice___
- 💼 LinkedIn — linkedin.com/in/parsa-jiravand
- ✉️ Email (work & contract inquiries): bestpractice2026@gmail.com
Originally published on dev.to