CSS Nesting

Native CSS nesting lets you write rules inside other rules, keeping a component's styles — its children, states and media queries — together in one block. It works in every current browser, with no preprocessor needed.

Basic nesting

Try it yourself
Result

A nested rule applies to matching descendants of the parent — .card h3 and .card p here.

The & selector

Try it yourself
Result

& stands for the parent selector. &:hover means .btn:hover, &.danger means .btn.danger, and .toolbar & flips the relationship: a .btn inside .toolbar.

Nesting media and container queries

Try it yourself
Result

Conditional rules can go straight inside a selector, keeping responsive changes next to the styles they modify. Combinator-led nested selectors like > * work without &.

What nesting compiles to

CSS nested.css
.nav {
  display: flex;

  a {
    color: inherit;

    &:hover {
      text-decoration: underline;
    }
  }
}

/* is equivalent to: */
.nav { display: flex; }
.nav a { color: inherit; }
.nav a:hover { text-decoration: underline; }

Differences from Sass

  • Native nesting can't concatenate strings: &__title to produce .card__title is a Sass feature, not CSS. Write .card__title out in full.
  • The nested selector behaves like :is(), which affects specificity: #main, .content { p { … } } gives the nested p rule the specificity of #main for both.

Don't nest too deeply

CSS too-deep.css
/* ✗ hard to read, high specificity, tied to the HTML structure */
.page {
  .main {
    .article {
      .content {
        p { color: #333; }
      }
    }
  }
}

/* ✓ flat and clear */
.article-content p {
  color: #333;
}

Nesting mirrors the HTML structure, and deep nesting creates long, specific, fragile selectors — the very problem it seems to solve. A good rule of thumb is to nest no more than two or three levels, mostly for states (&:hover), modifiers (&.active) and queries.

Try it yourself

Try it yourself
Result