CSS Nesting

CSS nesting lets you write related styles inside one another, mirroring the HTML structure they style. Instead of repeating a parent selector over and over, you write it once and nest child rules inside it. All modern browsers support native CSS nesting without any build tools or preprocessors.

The Problem Without Nesting

/* Without nesting — repetitive, disconnected rules */
.card { background: white; border-radius: 8px; }
.card h2 { font-size: 1.25rem; color: #333; }
.card p { color: #666; line-height: 1.6; }
.card .btn { background: blue; color: white; }
.card .btn:hover { background: darkblue; }
.card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
DIAGRAM — Selector repetition without nesting:

.card          ← type .card
.card h2       ← type .card again
.card p        ← type .card again
.card .btn     ← type .card again
.card .btn:hover ← type .card again
.card:hover    ← type .card again

Six rules, six repetitions of ".card"

The Same Code With Nesting

/* With nesting — grouped, readable, DRY */
.card {
  background: white;
  border-radius: 8px;

  h2 {
    font-size: 1.25rem;
    color: #333;
  }

  p {
    color: #666;
    line-height: 1.6;
  }

  .btn {
    background: blue;
    color: white;

    &:hover {
      background: darkblue;
    }
  }

  &:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  }
}
DIAGRAM — Nested CSS mirrors HTML structure:

HTML:                    CSS:
<div class="card">      .card {
  <h2>Title</h2>          h2 { ... }
  <p>Text</p>             p  { ... }
  <a class="btn">          .btn { ... }
  </a>                   }
</div>

The CSS shape matches the HTML shape — easy to read and maintain.

The & Selector — Parent Reference

The ampersand & refers to the parent selector. It is required when you need the parent and the nested selector to be joined with no space — for pseudo-classes, pseudo-elements, modifier classes, and attribute selectors.

DIAGRAM — With and without &:

.btn {
  &:hover { }   → compiles to: .btn:hover { }   ← joined (correct)
  :hover { }    → compiles to: .btn :hover { }  ← space added (wrong! targets children)
}

.btn {
  &.active { }  → compiles to: .btn.active { }  ← same element with two classes
  .active { }   → compiles to: .btn .active { } ← child with class active (different!)
}

Pseudo-Classes

a {
  color: blue;

  &:hover  { color: darkblue; text-decoration: underline; }
  &:focus  { outline: 2px solid blue; }
  &:visited { color: purple; }
}

Pseudo-Elements

h2 {
  position: relative;

  &::before {
    content: "";
    display: block;
    width: 40px;
    height: 3px;
    background: blue;
    margin-bottom: 8px;
  }
}

Modifier Classes (BEM Pattern)

.btn {
  background: blue;
  color: white;

  &--primary   { background: #3498db; }
  &--secondary { background: #95a5a6; }
  &--danger    { background: #e74c3c; }
  &--sm        { padding: 6px 12px; font-size: 0.85rem; }
  &--lg        { padding: 14px 32px; font-size: 1.1rem; }
}
DIAGRAM — BEM nesting compiles to:

.btn--primary   → .btn--primary { background: #3498db; }
.btn--sm        → .btn--sm { padding: 6px 12px; ... }

Nesting Media Queries

One of the most powerful uses of nesting is keeping responsive styles together with the component they affect.

/* Without nesting — responsive styles scattered */
.nav { flex-direction: row; }
@media (max-width: 768px) {
  .nav { flex-direction: column; }
}

/* With nesting — responsive styles inside the component */
.nav {
  display: flex;
  flex-direction: row;

  @media (max-width: 768px) {
    flex-direction: column;
  }
}
DIAGRAM — Responsive nesting keeps breakpoints next to their styles:

.card {
  display: grid;
  grid-template-columns: 1fr 1fr;    ← desktop: 2 columns

  @media (max-width: 600px) {
    grid-template-columns: 1fr;      ← mobile: 1 column
  }
}

Both rules live inside .card — easy to find and change.

Nesting At-Rules

.theme-card {
  background: white;
  color: black;

  @media (prefers-color-scheme: dark) {
    background: #1a1a1a;
    color: #f0f0f0;
  }

  @supports (backdrop-filter: blur(10px)) {
    background: rgba(255,255,255,0.8);
    backdrop-filter: blur(10px);
  }
}

Deep Nesting — How Deep is Too Deep?

/* Readable — 2 levels */
.card {
  .title { font-size: 1.25rem; }
  .body  { color: #666; }
}

/* Getting complex — 3 levels */
.nav {
  .menu {
    .item {
      &:hover { color: blue; }
    }
  }
}

/* Avoid — 4+ levels creates very high specificity */
.page {
  .section {
    .card {
      .title {
        span { ... }  /* ← .page .section .card .title span — too specific */
      }
    }
  }
}
DIAGRAM — Nesting depth recommendation:

Level 1: .component { ... }        ← always fine
Level 2:   .child { }              ← fine
Level 3:     .grandchild { }       ← acceptable
Level 4+:      .great-grandchild { } ← reconsider structure

Keep nesting to 2–3 levels. Deeper nesting creates high-specificity selectors that are hard to override and signals that your HTML structure might need simplifying.

Using & to Reverse Context

You can use & at the end or middle of a rule to flip the relationship — selecting the parent based on a parent-of-parent condition.

.btn {
  color: blue;

  /* Select .btn when it's inside .dark-theme */
  .dark-theme & {
    color: white;
  }
}

/* Compiles to: .dark-theme .btn { color: white; } */

A Full Component Example

.product-card {
  background: white;
  border: 1px solid #eee;
  border-radius: 10px;
  overflow: hidden;
  transition: box-shadow 0.3s;

  &:hover {
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
  }

  .card-image {
    width: 100%;
    height: 200px;
    object-fit: cover;
  }

  .card-body {
    padding: 16px;

    h3 {
      font-size: 1rem;
      margin-bottom: 8px;
    }

    .price {
      font-weight: 700;
      color: #e74c3c;
    }
  }

  .card-footer {
    padding: 12px 16px;
    border-top: 1px solid #f0f0f0;
    display: flex;
    justify-content: space-between;
  }

  @media (max-width: 480px) {
    .card-image { height: 150px; }
    .card-body  { padding: 12px; }
  }
}

Browser Support

Native CSS nesting is supported in all modern browsers — Chrome 112+, Firefox 117+, Safari 16.5+. For older browser support, use PostCSS with the nesting plugin to compile nested CSS to flat CSS automatically.

CSS Nesting vs Sass Nesting

FeatureNative CSS NestingSass Nesting
Build step neededNoYes
Works in browser as-isYesNo — compiles to CSS
SyntaxRequires & for direct joins& works identically
Nested media queriesYesYes

CSS nesting reduces repetition, keeps related rules together, and makes stylesheets easier to read and maintain. Use it for component styles — especially when combining element selectors, pseudo-classes, modifiers, and responsive breakpoints inside a single block.

Leave a Comment

Your email address will not be published. Required fields are marked *