On this page
Native CSS Nesting
Native CSS Nesting: Write Cleaner Styles Without Sass
Focus keyword: CSS nesting. Native CSS nesting lets you write a rule inside another rule, so related styles stay together and selectors are not repeated. It works directly in the browser with no preprocessor. In this lesson you will learn the syntax, the nesting selector &, nested at-rules, how specificity is calculated, how it differs from Sass and the mistakes to avoid.
Trending keywords covered in this lesson
native CSS nesting, CSS nesting selector, ampersand in CSS, CSS nesting vs Sass, nested media queries, nesting with container queries, CSS nesting specificity, relaxed nesting syntax, CSS nesting browser support, BEM with nesting, component CSS, nesting with @layer, nesting :is() behavior, nesting hover and focus, CSS without preprocessor, nested declarations.
1. The Problem Nesting Solves
Without nesting, you repeat the parent selector again and again: .card, .card h2, .card p, .card:hover. This is long, easy to break and hard to read. Nesting groups the rules of a component in one block so the structure of the CSS looks like the structure of the HTML.
2. Basic Syntax
Place a child rule inside the parent rule block. The browser joins the selectors for you. .card { padding: 1rem; h2 { margin: 0; } } is the same as .card h2 { margin: 0; }. Modern browsers support the relaxed syntax, so you can nest element selectors, class selectors, attribute selectors and pseudo-classes directly. Older versions of the specification required the & symbol before an element selector, so use it when you need wide compatibility.
3. The Nesting Selector &
The & symbol stands for the parent selector. It is essential in these cases:
- Pseudo-classes and pseudo-elements:
&:hover,&:focus-visible,&::before. Without &,:hoverwould mean a descendant in hover state. - Compound selectors on the same element:
&.activetargets the parent when it also has the class active. - Parent context (reverse nesting):
.dark &means a parent with class dark that contains the current element. - Sibling and other combinators:
& + &targets an element next to another element with the same selector. A child rule can also begin with a combinator such as> lior+ p.
4. What You Cannot Do
Native nesting does not support Sass-style string joining. &-title or &__item does not create .card-title or .card__item. The ampersand is a real selector reference, not text. For BEM names, write the full class: .card { .card__title { ... } } or use attribute-friendly structures. There are also no Sass variables, mixins, functions or loops, because native CSS uses custom properties and its own functions for those jobs.
5. Nesting At-Rules
You can place @media, @supports, @container and @layer inside a rule. The declarations inside belong to the parent selector. This keeps the responsive behavior of a component next to the component itself: .card { padding: 1rem; @media (min-width: 700px) { padding: 2rem; } }.
6. Specificity with Nesting
The browser treats a nested rule as if the parent were wrapped in :is(). That has two consequences:
- A nested rule has the specificity of the parent selector plus the nested selector, for example
.card .titleis (0,2,0). - If the parent is a selector list, such as
.card, #hero, the parent part takes the specificity of the most specific item in the list, which is the id (1,0,0). This can make a nested rule stronger than you expect.
Nested rules do not add a magic priority. Order in the file and specificity still decide, so avoid deep nesting and avoid mixing ids in selector lists.
7. Order of Declarations and Nested Rules
Write your normal declarations first and your nested rules after them. Declarations that appear after a nested rule are supported in current browsers, but they are treated as a separate group in the cascade and older browsers handle them differently. Keeping declarations first is easier to read and safer across browsers.
8. Nesting vs Sass
- Native nesting runs in the browser and works with live custom properties.
- No build step is required.
- No suffix joining with &.
- No mixins, functions or loops, so keep Sass if you need them.
- Keep nesting shallow. Two or three levels are enough. Deep nesting creates long selectors that are hard to override.
9. Browser Support and Fallback
Native CSS nesting is supported in all current major browsers, and it became widely available in 2023. If you must support older browsers, compile the nested CSS with a tool such as PostCSS, Lightning CSS or Sass. An important detail: a browser that does not understand nesting drops the nested rules but keeps the parent declarations, so the page stays usable.
10. Best Practices
- Nest by component, not by page. One top-level block per component.
- Stay within two or three levels.
- Use classes for nested rules, not long chains of element selectors.
- Put states and media queries inside the component they belong to.
- Combine nesting with
@layerso components do not fight with utilities.
11. Common Mistakes
- Writing
:hoverinstead of&:hoverand targeting a descendant by mistake. - Expecting
&-suffixto join class names like Sass. - Nesting five or six levels deep and creating specificity problems.
- Forgetting that a parent list with an id raises the specificity of every nested rule.
- Placing declarations after many nested rules and making the file hard to read.
- Using nesting for a page with old browsers without a compile step.
Key Takeaways
Native CSS nesting groups related rules, removes repeated selectors and works without a build tool. Use & for states, compound selectors and parent context, nest media and container queries inside the component, remember it is not string concatenation like Sass, keep the depth low and watch specificity.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Rewrite the flat CSS using native nesting. Put the a, a:hover and a.active rules inside .menu, and use the ampersand where it is needed.
Press Run to execute.
Show expected output
A single .menu block with nested a, &:hover and &.active rules, and the same visual resultThis is a self-check — compare your result with the expected output above.
Inside the .cards rule, add a nested media query that changes the grid to two columns from 600px and four columns from 1000px. Do not write a separate top-level media query.
Press Run to execute.
Show expected output
The .cards rule contains nested @media (min-width: 600px) and @media (min-width: 1000px) blocks that change grid-template-columnsThis is a self-check — compare your result with the expected output above.
Was this page helpful?