CSS Nesting

When we use a CSS preprocessor like Sass or Less, we can nest a CSS style rule within another rule to write clean and understandable code. This nesting rule is now supported in native CSS. Before nesting, every selector needed to be explicitly declared, separately from one another. This leads to repetition, stylesheet bulk and a scattered authoring experience.

.nesting {
  color: green;
}
​
.nesting > .is {
  color: red;
}
​
.nesting > .is > .awesome {
  color: blue;
}

After nesting, selectors can be continued and related style rules to it can be grouped within

.nesting {
  color: green;
​
  > .is {
    color: red;
​
    > .awesome {
      color: blue;
    }
  }
}

Pretty cool right?

Nesting helps developers by reducing the need to repeat selectors while also co-locating style rules for related elements. It can also help styles match the HTML they target. If the .nesting component in the previous example was removed from the project, you could delete the entire group instead of searching files for related selector instances.

Nesting can help with:

  • Organization
  • Reducing file size
  • Refactoring

CSS nesting allows you to define styles for an element within the context of another selector.

.parent {
  color: blue;
​
  .child {
    color: red;
  }
}

In this example, the .child class selector is nested within the .parent class selector. This means that the nested .child selector will only apply to elements that are children of elements with a .parent class.

This example could alternatively be written using the & symbol, to explicitly signify where the parent class should be placed. Nesting classes without & will always result in descendant selectors. Use the & symbol to change that result.

.parent {
  color: blue;
​
  & .child {
    color: red;
  }
}

Nesting @media

It can be very distracting, confusing, maddening to move to a different area of the stylesheet to find media query conditions that modify a selector and its styles. That distraction is gone with the ability to nest the conditions right inside the context.

For syntax convenience, if the nested media query is only modifying the styles for the current selector context, then a minimal syntax can be used.

.card {
  font-size: 1rem;
​
  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

All examples up to this point have continued or appended to a previous context. You can completely change or rearrange the context if needed.

The & symbol represents a reference to a selector object (not a string) and can be placed anywhere in a nested selector. It can even be placed multiple times. The example below may not be the best, but I am sure there are certain scenarios where this will be handy!

.card {
  .featured & {
    /* .featured .card */
  }
}
​
.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

Now for a few quirks, invalid nesting examples

HTML elements currently require the & symbol in front or being wrapped with :is().

.card {
  h1 {
    /* 🛑 h1 does not start with a symbol */
  }
}
​
.card {
  & h1 {
    /* ✅ now h1 starts with a symbol */
  }
​
  /* or */
​
  :is(h1) {
    /* ✅ now h1 starts with a symbol */
  }
}

Many CSS class naming conventions count on nesting being able to concatenate or append selectors as if they were strings. This does not work in CSS nesting as the selectors are not strings, they’re object references.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

CSS Nesting is only at version 1. Version 2 will introduce more syntactic sugar and potentially fewer rules to memorize. There’s a lot of demand for the parsing of nesting to not be limited as well!

Nesting is a big enhancement to the CSS language. Right?

Leave a comment