Happiness Without Sass: Clean Selectors with Native CSS Nesting
For years we leaned on preprocessors like Sass, Less, and Stylus to make CSS more readable. But we’re no longer bound to build steps, Node packages, and complex configs. 🥳
Browsers finally said “okay, we got it” and now provide nested selector support natively.
Welcome to a brand-new CSS era!
This Code (Largely) Works As-Is Now!
.card {
color: black;
& h2 {
font-size: 2rem;
}
& a:hover {
text-decoration: underline;
}
}
This syntax used to be Sass-only; now it runs directly in modern browsers. Even in a plain .css file, the browser understands it—no compilation required.
I say “largely” because a few browser versions still lack support. You’re safe on Chrome 120+, Edge 120+, Firefox 117+, and Safari 17+.
Under the hood, browsers expand it to:
.card {
color: black;
}
.card h2 {
font-size: 2rem;
}
.card a:hover {
text-decoration: underline;
}
Cleaner, more organized, and faster—life without Sass.
How It Works
Nesting lets you define selectors inside other rules.
The & symbol represents the parent selector.
You can group a component’s child styles in one block and preserve visual hierarchy.
Example:
.button {
background: blue;
& span {
color: white;
}
&:hover {
background: darkblue;
}
}
This automatically becomes button span and button:hover.
Your code is shorter, and the context is much clearer.
Advantages
- No dependencies: No need for Sass, Less, etc.
- More readable: Keep a component’s styles together.
- Easier maintenance: Scope and ownership stay obvious.
- Performant: Parsed directly by the browser.
- Great for component architectures: Plays nicely with React, Vue, Svelte.
Media Queries and States
CSS Nesting can cover media queries and states too. For example:
.card {
padding: 1rem;
background: white;
@media (max-width: 600px) {
& {
background: lightgray;
padding: 0.5rem;
}
}
}
Now the .card component’s desktop and mobile styles live in a single block. 👌
Pseudo-elements and states are fully supported as well:
.button {
&::before {
content: '👉';
}
&:active {
transform: scale(0.98);
}
}
⚠️ Things to Watch
- Native CSS Nesting is still relatively new.
- It works well on Chrome 120+, Edge 120+, Safari 17+, Firefox 117+.
- For older browsers (notably old Safari or Android WebView), consider polyfills via PostCSS
postcss-nestingorpostcss-preset-env. - Excessive nesting (5–6 levels) can hurt readability and create specificity issues.
Real-World Scenario
Say your design system has components like .card, .modal, and .button. Instead of scattering rules, you can manage them in one nested block:
.modal {
display: flex;
justify-content: center;
& .content {
background: white;
padding: 2rem;
& h2 {
font-size: 1.5rem;
}
}
&.active {
opacity: 1;
}
}
This works great in both React/Vue projects and vanilla CSS.
Folders stay tidy, style management speeds up.
Conclusion
The era of nested CSS without Sass has officially begun!
Now it’s fewer tools, more browser power.
CSS has finally become as modular and smart as JavaScript.
In short: Goodbye compilers, hello native CSS!