CSS Nesting

Write child rules directly inside their parent. Avoid repetition and make your stylesheets reflect your HTML structure.

CSS4 min readConcept 36 of 43

Grouping related styles together

Native CSS nesting allows you to place CSS rules inside other CSS rules. Instead of repeating the parent selector multiple times, you write it once and nest the child selectors inside.

This mirrors the nested structure of HTML, making your stylesheet much easier to read and maintain.

For years, developers relied on CSS preprocessors like Sass or Less to get this feature. Today, it is built natively into all modern browsers.

Less repetition, easier maintenance

Without nesting, a component's styles are scattered across independent rules: .card, .card h2, .card .button. If you rename the .card class, you have to update it in every selector.

With nesting, the parent is declared once. Everything related to the component lives neatly inside its block. This makes refactoring significantly safer and faster.

It also makes it immediately obvious which styles belong to a specific component, acting as natural encapsulation.

Using the nesting selector (&)

To nest a descendant, you simply write the child selector inside the parent's curly braces. For example, article { p { color: gray; } } targets paragraphs inside articles.

If you need to chain a pseudo-class or pseudo-element directly to the parent, use the ampersand &. Writing .btn { &:hover { } } correctly targets the button itself when hovered.

The & represents the parent selector. You can also use it to invert the relationship: .dark-theme & { } means "when the parent is inside a dark-theme container".

Try it

Watch how a deeply nested CSS rule expands into its flat, traditional CSS equivalent.

Basic nesting (descendants)

/* Nested CSS */
.card {
  padding: 1rem;
 
  h2 {
    color: blue;
  }
}

Flat equivalent

.card { padding: 1rem; }
.card h2 { color: blue; }
When a selector is nested directly, the browser compiles it as a standard descendant selector. The child rule is appended to the parent.

The parent reference selector (&)

/* Using the ampersand */
.button {
  background: blue;
 
  &:hover {
    background: red;
  }
}

Flat equivalent

.button { background: blue; }
.button:hover { background: red; }
The & explicitly references the parent selector. This is critical for pseudo-classes. Without the ampersand, .button :hover would target any hovered descendant instead of the button itself.

Specificity behaves like :is()

/* Multiple parent selectors */
#nav, .menu {
  a {
    color: teal;
  }
}

Flat equivalent

:is(#nav, .menu) a { color: teal; }

Specificity Warning

Under the hood, nested rules act like the :is() pseudo-class. The rule takes the specificity of the most specific parent (the #nav ID), even when matching the weaker .menu class.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1How do you apply a hover state to a `.button` from inside its nested block?
  2. 2True or False: In native CSS, you can write `&-icon` inside `.card` to automatically generate the `.card-icon` class.
  3. 3How is the specificity of a nested rule calculated?

Remember this

  • Native nesting groups related styles, making stylesheets mirror the HTML structure.
  • Use the & selector to explicitly chain pseudo-classes like &:hover or pseudo-elements.
  • Unlike Sass, native CSS nesting cannot concatenate strings to build class names.
  • Nested rules calculate their specificity using the :is() function behavior.

Done with this concept?

Mark it complete to track your progress. No login needed.