# Native CSS Nesting

> Native CSS nesting works without Sass. Learn basic nesting, the ampersand selector, nested media queries, specificity gotchas, and when to drop preprocessors.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-08-20 | Topics: [CSS](https://flaviocopes.com/tags/css/) | Canonical: https://flaviocopes.com/css-nesting/

Native CSS nesting lets you group related selectors without Sass or Less.

The browser understands the nested rules directly. There is no compilation step, generated CSS file, or source map involved.

Nesting does not replace the cascade. It only changes how you organize selectors. The same [specificity](https://flaviocopes.com/css-specificity/), inheritance, and source-order rules still apply.

## Start with a card

Here is a flat set of component styles:

```css
.card {
  padding: 1rem;
  border: 1px solid #ddd;
}

.card h2 {
  margin: 0;
  font-size: 1.25rem;
}

.card a {
  color: royalblue;
}
```

Move the descendant selectors inside `.card`:

```css
.card {
  padding: 1rem;
  border: 1px solid #ddd;

  h2 {
    margin: 0;
    font-size: 1.25rem;
  }

  a {
    color: royalblue;
  }
}
```

The result is still `.card h2` and `.card a`. The nesting makes the relationship visible in the stylesheet.

This works with any valid nested [selector](https://flaviocopes.com/css-selectors/):

```css
.article {
  > header {
    border-bottom: 1px solid #ddd;
  }

  h2 + p {
    margin-top: 0;
  }

  [aria-current="page"] {
    font-weight: bold;
  }
}
```

The `>` and `+` combinators keep their normal meaning. Nesting does not make every selector a direct child.

## Use & for the parent selector

The `&` symbol represents the selector of the outer rule.

Use it for [pseudo-classes](https://flaviocopes.com/css-pseudo-classes/):

```css
.button {
  background: royalblue;
  color: white;

  &:hover {
    background: navy;
  }

  &:focus-visible {
    outline: 3px solid orange;
    outline-offset: 3px;
  }
}
```

The nested selectors become `.button:hover` and `.button:focus-visible`.

You can also combine a class with the parent:

```css
.button {
  &.danger {
    background: firebrick;
  }

  &[aria-pressed="true"] {
    box-shadow: inset 0 0 0 2px white;
  }
}
```

These become `.button.danger` and `.button[aria-pressed="true"]`.

## Put the parent in a different position

The `&` can appear later in the selector.

For example, change a card when its parent has a dark theme:

```css
.card {
  background: white;
  color: #222;

  .dark-theme & {
    background: #222;
    color: white;
  }
}
```

This produces `.dark-theme .card`.

This pattern is useful for theme containers, layout contexts, and feature classes. Use it carefully. If a component depends on many distant ancestors, the nesting can hide that dependency.

## Native nesting is not Sass nesting

Do not copy every Sass pattern into native CSS.

Sass often uses `&` to build a new class name:

```scss
.card {
  &__title {
    font-weight: bold;
  }
}
```

That creates `.card__title` in Sass. Native CSS does not use `&` as text substitution, so this concatenation is invalid.

Write the class explicitly:

```css
.card {
  .card__title {
    font-weight: bold;
  }
}
```

Or use a simpler class name that makes sense inside the component.

## Nest media and container queries

At-rules can live beside the styles they modify.

```css
.sidebar {
  width: 100%;

  @media (min-width: 768px) {
    width: 18rem;
  }
}
```

The `@media` block applies to `.sidebar`. You do not repeat the selector.

The same pattern works with container queries:

```css
.product-card {
  display: grid;
  gap: 1rem;

  @container (min-width: 32rem) {
    grid-template-columns: 10rem 1fr;
  }
}
```

Keeping responsive changes near the base rule makes small components easier to understand. Read [CSS media queries](https://flaviocopes.com/css-media-queries/) if you need a refresher on responsive conditions.

## Be careful with selector lists

Native nesting uses the specificity behavior of `:is()` for a selector list.

Consider this rule:

```css
.card, #featured {
  .title {
    color: royalblue;
  }
}
```

It behaves like this:

```css
:is(.card, #featured) .title {
  color: royalblue;
}
```

The most specific selector inside `:is()` determines the specificity. Because the list includes `#featured`, the nested title rule gets ID-level specificity even when `.card` matches.

Avoid mixing IDs and classes in the same outer selector list. Separate them when you want predictable overrides:

```css
.card {
  .title {
    color: royalblue;
  }
}

#featured {
  .title {
    color: royalblue;
  }
}
```

## Do not nest everything

Deep nesting produces long selectors and tight coupling.

```css
.page {
  .content {
    .article {
      .card {
        a {
          color: royalblue;
        }
      }
    }
  }
}
```

That selector is difficult to reuse and difficult to override. Give the element a meaningful class and keep the nesting shallow:

```css
.article-card {
  a {
    color: royalblue;
  }
}
```

My rule is one or two levels for most component CSS. Nest when it reveals a relationship, not because the syntax allows it.

## When you can remove Sass

Native nesting covers one large reason projects adopted preprocessors. [CSS variables](https://flaviocopes.com/css-variables/) cover another.

You might remove Sass when your stylesheets use it only for:

- nested selectors
- color and spacing variables
- splitting files that your build tool already bundles

Keep the preprocessor when the project depends on loops, custom functions, generated utility classes, or a large mixin system. Removing it is useful only when it removes real complexity.

CSS nesting works in current browsers. Check your own browser support requirements before deleting an existing build step.

My advice is to use native nesting in new component styles. Leave stable flat CSS alone until you have another reason to edit it.
