What is CSS nesting? What are the practical use cases? Is it safe to use now?

DESI-1206-M01-2025-26-130

If you’ve ever written CSS, you know the pain. You start styling a navigation menu, and suddenly you’re typing header nav ul li a for the tenth time, wondering if there’s a better way. Spoiler: there is, and it’s called CSS nesting.

What Actually Is CSS Nesting?

CSS nesting is exactly what it sounds like – you can nest CSS selectors inside other selectors, creating a hierarchical structure that mirrors your HTML. Instead of repeatedly writing out parent selectors, you group related styles together in one logical block.

Here’s the thing that surprised me: this isn’t a new concept at all. Developers have been using nesting since 2006 through preprocessors like Sass. What’s new is that it’s now native to CSS – your browser understands it directly, no build tools required.

A Quick History Lesson (I Promise It’s Relevant)

Back in 2006, a developer named Hampton Catlin created Sass (Syntactically Awesome Style Sheets). One of Sass’s killer features was nesting. Soon after, Less CSS came along with similar capabilities. For nearly 17 years, if you wanted to write nested CSS, you had to:

  1. Write your styles in Sass or Less
  2. Set up a build process
  3. Compile it back to traditional CSS
  4. Hope nothing broke in the process

Developers loved nesting so much they were willing to add entire build tools to their workflow just to use it. That tells you something about how useful it is.

Then, in 2023, CSS nesting finally became native. Chrome, Edge, Safari, and Firefox all added support. No more preprocessors needed (well, unless you’re using Sass for other features like mixins, which is fair).

The Problem CSS Nesting Solves

Let me show you with a real example. Here’s how you’d traditionally style a navigation header:

css

header {
  background: #333;
  padding: 1rem;
}

header nav {
  display: flex;
  gap: 2rem;
}

header nav ul {
  list-style: none;
  display: flex;
}

header nav a {
  colour: white;
  text-decoration: none;
}

header nav a:hover {
  colour: #3498db;
}

Count how many times “header” appears. Five times! If you later decide to rename header to site-header, you need to find and replace it in five different places. Miss one, and your styles break.

Now here’s the same thing with CSS nesting:

css

header {
  background: #333;
  padding: 1rem;
  
  nav {
    display: flex;
    gap: 2rem;
    
    ul {
      list-style: none;
      display: flex;
    }
    
    a {
      colour: white;
      text-decoration: none;
      
      &:hover {
        colour: #3498db;
      }
    }
  }
}

Look at that. You write “header” once, and everything inside is automatically scoped to it. All your header-related styles are in one logical block. If you need to rename it, you change it in one place. That’s it.

The Ampersand (&) Is Your New Best Friend

Notice that &:hover in the nested example? That ampersand is crucial to understanding CSS nesting.

The & symbol represents the parent selector. When the browser sees it, it replaces it with whatever the parent is. So:

  • &:hover becomes a:hover
  • &:focus becomes a:focus
  • &::before becomes a::before

Here’s a more detailed example:

css

article {
  padding: 2rem;
  
  /* Creates: article h1 */
  h1 {
    font-size: 2rem;
  }
  
  /* Creates: article:hover */
  &:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  }
  
  /* Creates: article::before */
  &::before {
    content: "📄";
  }
}

Without the ampersand on h1, it creates a descendant selector (article h1). But with the ampersand, it applies the style to the article itself. This distinction is important – I got it wrong the first time I tried nesting and couldn’t work out why my hover states weren’t working!

Golden rule: Always use & before pseudo-classes (:hover, :focus, :active) and pseudo-elements (::before, ::after).

Real-World Use Case 1: Semantic HTML Structure

Let’s say you’re building a section with a header and some articles. Traditionally, your CSS would be scattered all over your stylesheet:

css

section { ... }
section header { ... }
section header h2 { ... }
section header p { ... }
section article { ... }
section article:last-child { ... }

That’s six separate selectors for one component. When you need to modify the section, you’re hunting through your entire CSS file.

With nesting, it’s all in one place:

css

section {
  padding: 3rem 1rem;
  
  header {
    margin-bottom: 2rem;
    
    h2 {
      font-size: 2.5rem;
      colour: #2c3e50;
    }
    
    p {
      colour: #7f8c8d;
      font-size: 1.1rem;
    }
  }
  
  article {
    margin-bottom: 1.5rem;
    line-height: 1.6;
    
    &:last-child {
      margin-bottom: 0;
    }
  }
}

Everything section-related is together. The visual hierarchy in your CSS matches the HTML structure. When I need to change how sections work, I know exactly where to look.

Real-World Use Case 2: Responsive Media Queries

This one’s a game-changer. Traditionally, media queries are scattered throughout your CSS file. You have your base styles at the top, then scroll down to find @media (min-width: 768px) somewhere in the middle, then another media query at the bottom. It’s chaos.

With nesting, media queries live right next to the styles they modify:

css

article {
  padding: 1rem;
  
  h1 {
    font-size: 1.5rem;
    margin-bottom: 1rem;
  }
  
  p {
    font-size: 1rem;
    line-height: 1.5;
  }
  
  @media (min-width: 768px) {
    padding: 2rem;
    
    h1 {
      font-size: 2.5rem;
    }
    
    p {
      font-size: 1.125rem;
      line-height: 1.7;
    }
  }
  
  @media (min-width: 1024px) {
    padding: 3rem;
    max-width: 800px;
    margin: 0 auto;
  }
}

Now I can see at a glance: mobile padding is 1rem, tablet is 2rem, desktop is 3rem. The heading grows from 1.5rem to 2.5rem. Everything about this article’s responsive behaviour is in one place.

When I’m working on responsive design, this saves so much time. No more jumping between different parts of the file trying to remember what changes at which breakpoint.

Browser Support (It’s Actually Good!)

Here’s the exciting bit: CSS nesting has excellent browser support as of 2025.

  • Chrome 112+ (April 2023)
  • Edge 112+ (April 2023)
  • Safari 16.5+ (May 2023)
  • Firefox 117+ (August 2023)

According to Can I Use, we’re looking at over 90% global browser support. For most modern projects, that’s production-ready.

I checked the Can I Use data myself whilst preparing my presentation, and the support is genuinely impressive. All major browsers adopted it within a few months of each other in 2023.

When Should You Use CSS Nesting?

Green light scenarios:

  • Modern web applications targeting 2023+ browsers
  • Internal tools and dashboards where you control the browser environment
  • Projects with defined browser requirements
  • Component-based architectures (React, Vue, etc.)

Proceed with caution:

  • Public-facing websites with diverse audiences
  • Clients specifically requiring older browser support
  • Projects where you don’t have analytics data on user browsers

Fallback option: If you need to support older browsers but still want to write nested CSS, use PostCSS with the postcss-nesting plugin. It’ll automatically transpile your nested CSS to traditional CSS during the build process. Best of both worlds.

Best Practices (Learn From My Mistakes)

1. Always Use the Ampersand for Pseudo-Classes

I learnt this the hard way. I forgot the & before :hover once and spent ages debugging why my hover states weren’t working. Don’t be like me.

css

/* ❌ Wrong - creates "article :hover" (note the space) */
article {
  :hover {
    background: red;
  }
}

/* ✅ Correct - creates "article:hover" */
article {
  &:hover {
    background: red;
  }
}

2. Don’t Nest Too Deeply

Maximum 3-4 levels. If you’re nesting more than that, your selectors become overly specific and hard to override.

css

/* ❌ Too deep - creates incredibly specific selectors */
main {
  section {
    article {
      header {
        h1 {
          /* This creates: main section article header h1 
             That's a specificity nightmare! */
        }
      }
    }
  }
}

/* ✅ Better - flatter structure */
main {
  section {
    padding: 2rem;
  }
  
  article {
    margin-bottom: 1rem;
  }
  
  h1 {
    font-size: 2rem;
  }
}

3. Use Nesting Where It Adds Value

Don’t nest just because you can. Only nest when it improves organisation and readability.

4. Keep an Eye on Specificity

Nesting increases specificity just like traditional nested selectors. main section h1 has the same specificity whether you write it traditionally or nested. Be mindful of this.

5. Test Across Target Browsers

Even though support is excellent, always test. I use BrowserStack for cross-browser testing in my projects.

Common Pitfalls to Avoid

Pitfall 1: Nesting Too Deeply

I already mentioned this in best practices, but it’s worth repeating because it’s the most common mistake. Five levels of nesting creates selectors like main section article header h1. That’s absurdly specific and nearly impossible to override without using !important (which you should avoid).

Pitfall 2: Forgetting the Ampersand

Without & before pseudo-classes, your styles won’t work as expected. The browser will look for a descendant element called :hover instead of applying the hover state to the parent.

Pitfall 3: Overusing Nesting

Just because you can nest doesn’t mean you should nest everything. If nesting doesn’t improve organisation, stick with traditional CSS.

Resources and Further Reading

If you want to dive deeper into CSS nesting, here are the resources I found most helpful:

My Personal Take

After using CSS nesting in a few recent projects, I genuinely can’t imagine going back to traditional CSS for component-heavy work. The organisation benefits alone are worth it.

That said, I wouldn’t use it absolutely everywhere. For simple, one-off styles, traditional CSS is perfectly fine. But for anything component-based – navigation menus, cards, forms, footers – nesting makes the code so much more maintainable.

The fact that it’s now native means there’s no excuse not to try it. You don’t need to set up Sass or any build tools. Just write nested CSS and it works.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *