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 not supported yet in native CSS. At the moment, it is a working draft and only available for discussion.

However, in this tutorial, we will 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.
Here’s what we’ll cover:
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 Sass and Less. As you can see from both code samples above, 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.
From the paragraph above, you can already see some advantages of using nesting. Let’s consider two more:
The question now is, “How can we use CSS nesting in native CSS?”
Nesting in native CSS is pretty much the same as we saw in the example above. However, in native, we must begin each nested selector with a “nesting selector” syntax, &, or we use the @nest rule.
If we rewrite the CSS code above with native CSS nesting, we will have the following:
.header {
background-color: blue;
& p {
font-size: 16px;
& span {
&:hover {
color: green
}
}
}
}
As mentioned earlier, the & is needed at the beginning of each selector for the nesting to be valid. We can think of the & as referencing the parent selector. That way, if we invert the above CSS style and replace every & with its parent selector, we will get back the initial CSS structure.
Similar to the above type selector, we can as well nest class selectors.
Let’s take another example. If we want to write compound selectors like the one below using native CSS nesting:
h1.header {
font-weight: 700
}
We do this:
h1 {
&.header {
font-weight: 700
}
}
As we can see, replacing the & with the parent selector, h1, gives us back the h1.header. Whenever we add a selector (in this case, a class selector) on the same element, we must ignore the space between & and the selector.
Let’s take another example. Let’s rewrite the following style rules using nested classes:
.foo { color: #000000; }
.foo .bar { color: #fd2020; }
.foo .bar > .baz { color: #ffffff; }
For the first nested class selector, we will have:
.foo {
color: #000000;
& .bar {
color: #fd2020;
}
}
And then, adding the second nested class gives us:
.foo {
color: #000000;
& .bar {
color: #fd2020;
& > .baz {
color: #ffffff;
}
}
}
The same method applies to nesting conditional rules such as media queries. Take a look at the following nested rules:
.header {
font-size: 40px
@media (max-width: 760px ) {
& {
font-size: 24px;
}
}
}
We can see that by replacing the & with the parent selector, .header, we will get the following equivalent:
.header {
font-size: 40px;
}
@media (max-width: 760px) {
.header {
font-size: 24px;
}
}
As we can see, CSS nesting helps in grouping similar styles together.
Imagine we have a group of selectors like so:
#header span,
#header a,
p span,
p a {
color: #0000ff;
}
First, with the CSS is() function, we can make the style rules a bit compact, like so:
:is(#header, p) span,
:is(#header, p) a {
color: #ff0000;
}
Then, to create nested style rules, we must begin each selector with &. In this case, we will have the following:
#header, p {
& span, & a { color: #ff0000; }
}
It doesn’t get simpler than this.
@nest ruleWhile 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.
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.
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.
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.
Nesting is an exciting feature that will soon be added to native CSS. In this article, we have discussed the following:
@nest ruleFor further study on CSS nesting, you can refer to the W3C draft for the CSS nesting module.
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.

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. 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 and mobile apps — start monitoring for free.
We investigate the concept of scroll-aware UI state for increased interactivity and explore how to implement it using only CSS.
Delve into Strapi’s features and more to understand when and why you should use this open source headless CMS for your next project.
Learn how to make visual regression tests easy and fast with Argos CI, an automation tool that compares screenshots during build time.
Use CSS Subgrid to design advanced and responsive grid layouts that are consistently aligned and independent of each other.
5 Replies to "Native CSS nesting: What you need to know"
Finally! Writing vanilla CSS has been a pain once you’re used to SCSS.
Now that’s a LOT of ampersands…
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
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; }
After writing Less, Sass, SCSS, Stylus, back to SCSS… and now spending a year with no pre-processor: it’s hard to imagine using this syntax. As huge fans of nesting… we can’t believe we’re come to a point where we might just prefer not to. If we could skip the & on every line, and we also had HTTP2 or something concatenate the files natively, maybe it would be a winner. We’ll cross our fingers for something better to happen… or wait to evolve our stance.