0%

Native CSS Nesting: Say Goodbye to Sass (For This, At Least)

CSS

If you’ve written Sass or Less, you know the comfort of nesting selectors inside one another instead of repeating parent selectors over and over. For years, that was a preprocessor-only luxury. Not anymore — CSS nesting is now part of the language itself, and browser support is excellent: Chrome and Edge 112+, Safari 16.5+, and Firefox 117+ all support it natively. If you’re targeting modern browsers, you can start using it today with zero build step.

The problem it solves

Without nesting, styling a card component with a few states means writing out .card again and again:

.card {
  padding: 1rem;
  border-radius: 8px;
}

.card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.card .card-title {
  font-weight: 600;
}

.card.is-active {
  border: 2px solid blue;
}

It works, but it’s repetitive, and it doesn’t visually communicate that these rules are all related to the same component.

The nested version

.card {
  padding: 1rem;
  border-radius: 8px;

  &:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  }

  .card-title {
    font-weight: 600;
  }

  &.is-active {
    border: 2px solid blue;
  }
}

Same result, but the relationships are obvious at a glance, and the browser parses this directly — no compile step required.

The & selector, and when you actually need it

The & refers back to the parent selector. For descendant selectors (like .card-title above), you can often skip it — the browser assumes descendant combination by default. But & becomes necessary in a few cases:

Compound selectors, where you’re attaching something directly to the parent rather than a descendant:

.button {
  &.is-disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
}

Without the &, .is-disabled { } inside .button would be parsed as a descendant selector (.button .is-disabled), not a compound one (.button.is-disabled) — a subtle but important difference.

Pseudo-classes and pseudo-elements:

.input {
  &::placeholder {
    color: #999;
  }

  &:focus-visible {
    outline: 2px solid dodgerblue;
  }
}

Nesting media queries and other at-rules

This is where things get genuinely nice. You can nest @media, @supports, and container queries right inside a rule, keeping responsive logic next to the styles it affects instead of in a separate block far away in the file:

.sidebar {
  width: 250px;

  @media (max-width: 768px) {
    width: 100%;
  }

  @supports (display: grid) {
    display: grid;
  }
}

A quick note on specificity

Nested rules resolve to roughly the same specificity as if you’d written them with :is() wrapping the parent. In practice, this means deeply nested selectors can rack up specificity faster than you’d expect, so it’s still worth keeping nesting shallow — two or three levels is a reasonable ceiling before things get hard to override.

Should you drop Sass?

For nesting specifically, probably yes, if your browser support target allows it. But Sass still offers things native CSS doesn’t have equivalents for yet — mixins, functions, loops, and module-style partials. Native CSS nesting closes one of the biggest gaps, not all of them.

Try it yourself

Open dev tools on any site right now and nest a rule inside .some-class { } in the inspector — if you’re on a modern browser, it’ll just work. No Sass, no PostCSS, no build step in the way.