ru
How to use native Nesting syntax in CSS (updated)

How to use native Nesting syntax in CSS (updated)

A year has passed since this article was written. Since then, the CSS Nesting specification has changed. There have been significant changes to it, so I'm posting an updated article.

The CSS Nesting syntax was significantly impacted by the nested selectors syntax of the Sass preprocessor. Many frontenders find it difficult to drop preprocessors in favor of native CSS, precisely because of the lack of nesting. In order to improve DX (developer experience) the CSS working group decided to introduce nested selectors.

Although the syntax is very similar, there are still some minor differences.

CSS syntax

Media queries inside nested selectors

For me, the most desired change was the ability to write media expressions inside nested selectors. For example, let's go back to the code described in the article about the new media expression syntax.

Classic variant:

.teaser__image {
  width: 100%;
}

@media (width < 620px) {
  .teaser__image {
    width: 100px;
  }
}

@media (620px <= width <= 768px) {
  .teaser__image {
    width: 180px;
  }
}

Using CSS nesting:

.teaser__image {
  width: 100%;

  @media (width < 620px) {
    width: 100px;
  }

  @media (620px <= width <= 768px) {
    width: 180px;
  }
}

Note that I am using the new media expression syntax. You can use the old syntax if you like.

The nested syntax makes the code much easier to read and more intuitive. Plus, it's a native browser behavior, and we won't need to install additional preprocessors like Sass, Less to achieve that behavior.

Nesting of selectors

This behavior is familiar from the preprocessors. A recent version of the specification introduced a change that removes the mandatory writing of the & ampersand.

.teaser__image {
  background: lightgray;

  img {
    display: block;
  }
}

figure {
  margin: 0;

  > figcaption {
    background: lightgray;

    > p {
      font-size: 0.9rem;
    }
  }
}

Although in some cases, the ampersand is mandatory.

button {
  &:hover {
    background-color: red;
  }

  &:focus {
    background-color: blue;
  }
}

More details on the syntax can be found in the specification.

Concatenation of strings

.block {
  color: blue;

  &__element {
    color: red;
  }
}

This behavior in CSS Nesting, as specified in the spec, will not work. Too many heuristics for browsers.

@nest rule is gone!

The @nest rule existed in early drafts of the specification, then after a user poll, it was removed.

More details about the syntax can be found in the specification.

Although the new syntax has already been approved, there is an online poll by the spec developers started recently, asking us to choose syntax options.

Enable the new syntax right now

Until the new syntax has reached full support for all browsers, we will enable the new features of the CSS Nesting specification using PostCSS.

Install the PostCSS plugin:

npm i -D postcss postcss-nesting

Create a file postcss.config.js to configure PostCSS.

const postcssNesting = require('postcss-nesting');

module.exports = {
  plugins: [postcssNesting],
};

As a result, the output of PostCSS code will be compiled into native CSS, understandable by all browsers.

I described more about how to connect PostCSS to Gulp, Eleventy, Nuxt in this article.

Note also that there is a postcss-nested plugin, but at the moment I prefer to use the postcss-nesting plugin, which correctly implements the latest version of the CSSWG specification.


References:

Last Updated: