CSS nesting has been supported in all major browsers for two years now. Yeah, two years already! Which means it’s finally safe to use in real projects. Back then, I mostly ignored it because I was already using Sass for nesting, the syntax was still a bit too restrictive, and support for older browser versions was still a concern. I’m sure we’ve all been guilty of lagging behind on updates.
Returning to it today, it turns out CSS nesting is actually pretty solid. So let’s take a look at how it works, when it makes sense to use it, and where it still falls short. If you prefer the video version, you can check it out below:
The Problem With Traditional CSS
Let’s start with a simple example: a “preview card” component.

The HTML
<!-- Card -->
<article class="preview-card">
<!-- Preview Card Image -->
<img src="https://picsum.photos/640/180" alt="random image">
<!-- Preview Card Body -->
<div class="pc-body">
<h2>CSS Nesting</h2>
<p>Lorem, ipsum...</p>
<a href="#">Learn More</a>
</div>
</article>Nothing fancy here – just a card, an image, and some content.
The Classic CSS Approach
With classic CSS, your styles might look something like this code below. Note that I am leaving out some styling properties to simplify it.
article.preview-card {
background-color: #ccc;
border-radius: 8px;
overflow: hidden;
}
article.preview-card img {
width: 100%;
}
article.preview-card .pc-body {
padding: 24px;
}
article.preview-card .pc-body p {
font-size: 18px;
}
article.preview-card .pc-body a {
background-color: #5755c0;
}This works… but it’s repetitive. When I first started writing CSS, I may have tried to “clean this up” by removing selectors like .pc-body from the p and a rules. But then the .pc-body, p, and a elements all look like they could be siblings.
This is exactly the problem Sass solved years ago with nesting, but it required a build step. Now we can do it directly in CSS.
CSS Nesting Has Been Supported for 2+ Years
If you check the Can I Use page for CSS nesting, you’ll see green across the major browsers: Chrome, Edge, Safari, and Firefox. The green cells also mean the relaxed syntax is supported (more on that later).
At this point, for most modern projects, CSS nesting is safe to use.
What Is CSS Nesting?
CSS nesting lets you write styles in a way that mirrors your HTML structure.
Here’s the same preview card rewritten using native CSS nesting:
article.preview-card {
background-color: #ccc;
border-radius: 8px;
overflow: hidden;
img {
width: 100%;
}
.pc-body {
padding: 24px;
p {
font-size: 18px;
}
a {
background-color: #5755c0;
}
}
}A few immediate benefits:
- No repeated selectors
- Much easier to scan
- The hierarchy is obvious – looks a lot like the HTML
And yes, it behaves exactly the same as the classic CSS version.
CSS Nesting vs Sass
If you’ve used Sass, this probably feels very familiar.
Nesting was one of the biggest selling points of Sass for me, and it still has a ton of value. With it, you get extra features like:
- Mixins
- Modules
- Custom functions
- Loops
- Private comments
If your project already has a build step, Sass is still a great choice. But it’s pretty cool that one of Sass’s best features is now built directly into CSS, no tooling required.
Now let’s dive deeper into how CSS Nesting works!
The Ampersand (&) Explained
The ampersand represents the parent selector – you can think of it as a substitute for it. Let’s take a look at how it’s used in some examples comparing classic CSS with the new nesting syntax.
Pseudo-classes & pseudo-elements
/* Classic CSS */
a:hover { }
a:focus { }
a::before { }
a:not(.active) { }
a:nth-child() { }
/* Nested CSS */
a {
&:hover { }
&:focus { }
&::before { }
&:not(.active) { }
&:nth-child() { }
}Chaining modifiers
/* Classic CSS */
span.message.warning { color: goldenrod; }
span.message.success { color: green; }
span.message.error { color: red; }
/* Nested CSS */
span.message {
&.warning { color: goldenrod; }
&.success { color: green; }
&.error { color: red; }
}Reverse Nesting
Sometimes the parent appears later in the selector:
/* Classic CSS */
li {
color: black;
}
.menu li {
color: white;
}
/* Nested CSS */
li {
color: black;
.menu & {
color: white;
}
}This one is less common and can be more confusing to interpret, but the pattern can still be useful. Just remember that the ampersand simply represents whatever the parent selector is.
Combinators
Combinators are pretty straight-forward and don’t require the &.
/* Classic CSS */
article.preview-card > img { /**/ }
article.preview-card + img { /**/ }
article.preview-card ~ img { /**/ }
/* Nested CSS */
article.preview-card {
> img { /**/ }
+ img { /**/ }
~ img { /**/ }
}You Don’t Need & for Basic Nesting Anymore
If the ampersand represents the parent, you may be wondering why you wouldn’t include the & in basic nesting like this:
article.preview-card {
background-color: #ccc;
border-radius: 8px;
overflow: hidden;
& img {
width: 100%;
}
& .pc-body {
padding: 24px;
& p {
font-size: 18px;
}
& a {
background-color: #5755c0;
}
}
}A couple years ago, you actually did need to write it out like that. But since then, browsers have updated to allow a more relaxed syntax, so the ampersand is now implied. This is also more in line with how nesting is written when using Sass.
Nesting @rules
Several at-rules can be nested, including:
@media@supports@layer@scope@container
Example: Nested Media Query
/* Classic CSS */
.pc-body {
padding: 24px;
}
@media (max-width: 1000px) {
.pc-body a {
background-color: green;
}
}
/* Nested CSS - Option A */
.pc-body {
padding: 24px;
@media (max-width: 1000px) {
a {
background-color: green;
}
}
}
/* Nested CSS - Option B */
.pc-body {
padding: 24px;
a {
@media (max-width: 1000px) {
background-color: green;
}
}
}Both options A and B do the same thing, so it’s a personal preference. It’s convenient to be able to simply target a nested child selector with a media query.
Some rules, like @keyframes or @font-face, can’t be nested. But those wouldn’t make sense to nest anyway.
Caveats & Limitations
1. Over-Nesting Is Real
body {
.page {
aside {
.preview-card {
.pc-body {
p {
a {
color: gray;
}
}
}
}
}
}
}At this level of specificity, styles become fragile and a small markup changes can break everything.
My rule of thumb: keep nesting to just a few levels or scoped to a component or section.
2. Older Browser Support
If you’re supporting legacy enterprise systems, you may still need to avoid nesting. For most modern projects, this isn’t an issue anymore.

3. BEM + CSS Nesting Doesn’t Work
If you used Sass like this:
.preview-card {
&__body { }
}That won’t work with native CSS nesting.
But if that syntax doesn’t even look familiar to you, there’s no need to worry about this!
Final Thoughts
So, will I be using CSS nesting?
Absolutely, but situationally.
I’ll still use Sass when I want its extra power, especially in larger projects with a build step. But native CSS nesting is perfect for:
- Small projects
- Prototypes
<style>tags in HTML files- Platforms that only allow custom CSS
As CSS continues to pick up features that used to require preprocessors, nesting is one more reason to periodically re-evaluate how you write your styles. It may not replace your current workflow, but it’s definitely worth understanding.

