Sarah Chima Atuonwu I am a Fullstack software developer that is passionate about building products that make lives better. I also love sharing what I know with others in simple and easy-to-understand articles.

Native CSS nesting: What you need to know

4 min read 1317

Native CSS Nesting

Native CSS will support CSS nesting. This is a really good feature for so many reasons, with one of the foremost being that it’s easier to write clean and understandable CSS code.

How is that so? Let us discuss what nesting is and how it is used in preprocessors. Then, we will discuss some of its advantages and how it will be used natively in CSS.

What is CSS nesting?

You may be familiar with writing CSS this way:

.header {
  background-color: blue;
}

.header p {
  font-size: 16px;
}
.header p span:hover{
  color: green
} 

Consider another way of writing these same styles with CSS nesting:

.header {
  background-color: blue;
  p {
    font-size: 16px;
    span {
      &:hover {
        color: green
      }
    }
  }
}

This syntax has been possible with CSS preprocessors like SCSS and Less. As you can see from both codes, nesting is enclosing a selector inside another selector. Nesting helps you to group related styles and write CSS in a nested hierarchy.

If you think this is different, consider that you have been doing this all along with HTML. So rather than writing the same selector over and over again to style specific children elements or pseudo-selectors, you can just nest them under a single selector.

Advantages of nesting

From the paragraph above, you can already see some advantages of using nesting. Let’s consider two more:

  1. Writing more modular and maintainable stylesheets. Rather than having the same selector in multiple places in a stylesheet, you can place all styles related to that selector in one place. This will make development time and debugging time much faster
  2. It allows you to nest media queries. With nesting, there’s no need to have a separate media query rule for a selector. You can add this right where you defined the selector

The question now is, “How can we use CSS nesting in native CSS?”

How to nest selectors in CSS

Nesting in CSS is pretty much the same as we saw in the example above. However, you need to begin each nested selector with an ampersand & or the @nest rule. Let’s rewrite the code above with native CSS nesting:

.header {
  background-color: blue;
  & p {
    font-size: 16px;
    & span {
      &:hover {
        color: green
      }
    }
  }
}

Notice the & at the beginning of each selector? This is needed in CSS for the nesting to be valid. Also, notice the &:hover stayed the same. There’s no need to add an extra & in this case.

We made a custom demo for .
No really. Click here to check it out.

Let’s take another example. If you want to write compound selectors like the one below using native CSS nesting:

h1.header {
  font-weight: 700
}

You do this:

h1 {
  &.header {
    font-weight: 700
  }
}

Notice that if you want to add a selector for a class on the same element, there is no space between the & and the selector.

This is an example of nesting media queries:

.header {
  font-size: 40px

  @media (max-width: 760px ) {
    & {
      font-size: 24px;
    }
  }
}

We can see how helpful this is in grouping similar styles together.

The @nest rule

While direct nesting with & may seem perfect, there are some valid nesting selectors that it fails to handle. Let’s consider an example:

.header {
  background-color: white;
  .dark & {
    background-color: blue; 
 }
}

The above nesting is valid for nesting selectors. But direct nesting in CSS is not able to handle it. This is where the @nest rule comes in.

The @nest rule allows nesting to be more flexible in CSS. So rather than having the nesting selector only at the beginning of the nested selector, the @nest rule allows nesting to be less constrained as long as there’s a nesting selector(&) in the nested selector.

The example above can be fixed using the @nest rule:

.header {
  background-color: white;
  @nest .dark & {
    background-color: blue; 
 }
}

This is equivalent to:

.header {
  background-color: white;
}

.dark .header {
    background-color: blue; 
}

Another example:

.header {
  background-color: white;
  @nest :not(&) {
    background-color: blue;
  }
}

This is equivalent to:

.header {
  background-color: white;
}

:not(.header) {
  background-color: blue;
}

Note that for the @nest rule to be valid, the direct nesting selector (&) must be present in the nested selector, or else it will be invalid. So the example below is not valid because there’s no nesting selector present.

.header {
  background-color: white;
  @nest .dark {
    background-color: blue; 
 }
}

N.B., CSS is not supported by all browsers now, but you can use PostCSS to convert your nested CSS to valid CSS that is understood by browsers.

CSS nesting and specificity

In CSS, specificity is a set of rules that determine which styles are applied to an element. If two or more selectors apply to the same element, the one with the highest specificity is applied. For instance, consider the example below:

<html>
  <h1 class="header" id="header" />
</html>

<style>
  #header {
    color: red;
  }
  .header {
    color: blue;
  }

  h1 {
    color: green;
  }
</style>

CSS cascades, so ideally the last selector applied in the stylesheet (h1) should be applied.
However, the color of the H1 element will be red, because the id selector(#header) has a higher specificity. For a more detailed explanation of specificity, you can read this detailed article on specificity.

How is this relevant to CSS nesting? Let’s take a look at what goes on in the browser when we use nesting. Consider this example:

#header, p {
  & span {
    color: red;
  }
}

This is equivalent to:

:is(#header, p) span (color: red)

The :is selector uses the highest specificity among the selector for all the selectors, so it will be difficult to override the styles. If you have a p element you want to change the color of the span, for example, like this below:

<p class="paragraph">
  <span>hey there <span>
</p>

<style>
  #header, p {
    & span {
      color: red;
    }
  }
 .paragraph {
    & span {
      color: green;
    }
  }
</style>

The color red will still be applied because the specificity of the #header is higher than that of the class .paragraph.

This is important to avoid resorting to very complex selectors or the use of !important to overwrite styles. Next, let’s consider some general guidelines to follow with nesting.

Common guides in using nesting

Avoid over-nesting

Since nesting makes it easy to nest styles, you may be tempted to over-nest selectors. Consider the example below:

main {
  & section {
    background-color: red;
    & ul {
        background-color: green;
        & .list {
          font-size: 16px;
          & .link {
            color: pink;
              & :hover {
                color: blue
              }
          }
        }
      }
  }
}

This is equivalent to

main section {
  background-color: red;
}

main section ul {
  background-color: green;
}

main section ul .list{
  font-size: 16px;
}

main section ul .list .link{
  color: pink;
}

main section ul .list .link:hover{
  color: blue;
}

The last selector has six levels of nesting. This can lead to a lot of specificity issues if you ever want to override the styles. As a general guide, keep nesting only three levels deep. You can use stylelint to keep this in check. Prefer to use classes with descriptive names as much as possible.

Styles after nested selectors are ignored

This is good to keep in mind when using nesting. Consider this example:

main {
  & section {
    background-color: red;
  }
  color: green;
}

The color: green will be ignored since it is after the nested selector. With CSS nesting, any styles should be applied before the nested selectors. This is one difference between CSS nesting and nesting with other preprocessors.

Conclusion

Nesting is an exciting feature that will soon be added to native CSS. In this article, we have discussed the following:

  • Nesting will help to keep stylesheets modular and more maintainable. This is because with nesting, all styles related to a selector, children/parent selector, and even media queries can be nested in the same place
  • How and when you can use direct nesting and the @nest rule
  • Why you should keep specificity in mind while using nesting and avoid over-nesting

For further study on CSS nesting, you can refer to the W3C draft for the CSS nesting module.

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — .

Sarah Chima Atuonwu I am a Fullstack software developer that is passionate about building products that make lives better. I also love sharing what I know with others in simple and easy-to-understand articles.

4 Replies to “Native CSS nesting: What you need to know”

  1. Maybe not best to use it unless totally necessary, as SCSS still has advantages of not requiring to use that many ampersands in the code. And it can easily be forgotten or that it can catch errors before the compiling has completed. And also that we have modules that we can work from which would make it ideal. But either way would be good to have that as native.

    Kind regards,
    Michael

  2. BBEdit can reformat these before and after examples to be much easier to understand. For instance, here’s the over-nested example:

    main
    {
    & section { background-color: red;
    & ul { background-color: green;
    & .list { font-size: 16px;
    & .link { color: pink;
    &: hover { color: blue;
    }

    main section { background-color: red; }
    main section ul { background-color: green; }
    main section ul .list { font-size: 16px; }
    main section ul .list .link { color: pink; }
    main section ul .list .link:hover { color: blue; }

Leave a Reply