TH The Sass Way
Tooling & Workflow

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

Native CSS Nesting vs Sass Nesting: What Changed and What to Use
tldrSass nesting is a build-time feature that compiles to flat CSS and glues selectors as text, so `&__title` becomes `.card__title`. Native CSS nesting is a real browser feature with no build step, where `&` is a live selector reference that behaves like `:is()` and cannot do BEM concatenation. For new projects on modern browsers, native CSS nesting is usually enough.

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:

  1. 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.
  2. Prefix nested selectors with & or a combinator. Writing & .title rather than a bare .title keeps intent obvious and avoids the oldest parser edge cases.
  3. 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.
  4. Keep @media and @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:

Rules that apply to both

Whichever you choose, the same nesting mistakes bite you.

Which should you use?

A quick decision guide:

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.

FAQ

Does CSS support nesting natively now?

Yes. Native CSS nesting is Baseline widely available in 2026. The `&` nesting syntax shipped in Chrome 112, Safari 16.5, and Firefox 117 back in 2023, and the relaxed syntax that lets a nested rule start with a bare element selector followed shortly after. No preprocessor or build step is required in any current evergreen browser.

Is Sass still needed if CSS has nesting?

Only if you use more than nesting. Native CSS nesting replaces Sass nesting for most projects, but Sass also provides variables, mixins, functions, `@each` loops, maps, and partials that CSS has no built-in equivalent for. If nesting was the single reason you used Sass, you can drop it. If you rely on the rest of the language, keep Sass.

What is the difference between & in CSS and Sass?

In Sass, `&` is literal text substitution done at compile time, so `&__title` concatenates into `.card__title`. In native CSS, `&` is a live selector reference that behaves like the `:is()` pseudo-class. It cannot concatenate strings, so BEM-style `&__element` naming does not work, and its specificity equals the highest selector in the parent list.

Can native CSS nesting do BEM concatenation?

No. BEM naming like `&__title` or `&--featured` only works in Sass, where `&` is glued to the following text before compilation. In native CSS, `&` is a selector, so `&__title` does not build `.card__title` and matches nothing useful. To use BEM with native nesting, write the full class names out flat or keep those files in Sass.

Can you nest media queries in native CSS?

Yes. Both native CSS nesting and Sass let you nest `@media` and `@container` queries directly inside a rule, keeping a component's responsive styles next to the component instead of at the bottom of the file. The syntax is nearly identical in both, and native CSS handles container queries this way too, which suits component-based responsive design.

How do I convert Sass nesting to native CSS?

Most nesting ports directly. The two things that break are BEM concatenation (`&__`, `&--`), which you must expand into full class names, and parent selector lists mixing IDs and classes, whose specificity changes because native `&` acts like `:is()`. Plain grouping, `&:hover`, and nested media queries translate one-to-one. Use `postcss-nesting` if you need old-browser output.