CSS Nesting Stay organized with collections Save and categorize content based on your preferences.
One of our favorite CSS preprocessor features is now built into the language: nesting style rules.
Before nesting, every selector needed to be explicitly declared, separately fromone another. This leads to repetition, stylesheet bulk and a scattered authoringexperience.
.nesting{color:hotpink;}.nesting>.is{color:rebeccapurple;}.nesting>.is>.awesome{color:deeppink;}
Afternesting, selectors can becontinued and related style rules to it can be grouped within.
.nesting{color:hotpink;>.is{color:rebeccapurple;>.awesome{color:deeppink;}}}
Nesting helps developers by reducing the need to repeat selectors while alsoco-locating style rules for related elements. It can also help styles match theHTML they target. If the.nesting
component in the previous example wasremoved from the project, you could delete the entire group instead of searchingfiles for related selector instances.
Nesting can help with:- Organization- Reducing file size- Refactoring
Nesting is available from Chrome 112 and also available totry in Safari Technical Preview 162.
Getting started with CSS Nesting
Throughout the rest of this post,the following demo sandbox is used to help youvisualize the selections. In this default state, nothing is selected andeverything is visible. By selecting the various shapes and sizes, you canpractice the syntax and see it in action.
Inside the sandbox are circles, triangles, and squares. Some are small, mediumor large. Others are blue, pink or purple. They're all inside the.demo
containing element. The following is a preview of the HTML elements you'll betargeting.
<div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> …</div>
Nesting examples
CSS nesting allows you to define styles for an element within the context ofanother selector.
.parent{color:blue;.child{color:red;}}
In this example, the.child
class selector is nested withinthe.parent
class selector. This means that the nested.child
selector willonly apply to elements that are children of elements with a.parent
class.
This example could alternatively be written using the&
symbol, to explicitlysignify where the parent class should be placed.
.parent{color:blue; &.child{color:red;}}
These two examples are functionally equivalent and the reason you have optionswill become clearer as more advanced examples are explored in this article.
Selecting the circles
For this first example, the task is to add styles to fade and blur just thecircles inside the demo.
Without nesting, CSS today:
.demo.circle{opacity:.25;filter:blur(25px);}
With nesting, there are two valid ways:
/* & is explicitly placed in front of .circle */.demo{ &.circle{opacity:.25;filter:blur(25px);}}
or
/* & + " " space is added for you */.demo{.circle{opacity:.25;filter:blur(25px);}}
The result, all the elements inside.demo
with a.circle
class areblurred out and nearly invisible:

Selecting any triangles and squares
This task requires selecting multiple nested elements, also called agroup selector.
Without nesting, CSS today, there are two ways:
.demo.triangle,.demo.square{opacity:.25;filter:blur(25px);}
or, using:is()
/* grouped with :is() */.demo:is(.triangle,.square){opacity:.25;filter:blur(25px);}
With nesting, here are two valid ways:
.demo{ &.triangle, &.square{opacity:.25;filter:blur(25px);}}
or
.demo{.triangle,.square{opacity:.25;filter:blur(25px);}}
The result, only.circle
elements remain inside.demo
:

Selecting large triangles and circles
This task requires acompound selector, whereelements must have both classes present in order to be selected.
Without nesting, CSS today:
.demo.lg.triangle,.demo.lg.square{opacity:.25;filter:blur(25px);}
or
.demo.lg:is(.triangle,.circle){opacity:.25;filter:blur(25px);}
With nesting, here are two valid ways:
.demo{.lg.triangle,.lg.circle{opacity:.25;filter:blur(25px);}}
or
.demo{.lg{&.triangle,&.circle{opacity:.25;filter:blur(25px);}}}
The result, all the large triangles and circles are hidden inside.demo
:

Pro tip with compound selectors and nesting
The&
symbol is your friend here as it shows explicitly how to adjoin nestedselectors. Consider the following example:
.demo{.lg{.triangle,.circle{opacity:.25;filter:blur(25px);}}}
While a valid way to nest, the results won't match the elements you may expect.The reason is that without&
to specify the desired outcome of.lg.triangle,.lg.circle
compounded together, the actual result would be.lg .triangle, .lg.circle
;descendant selectors.
&
will always result in descendant selectors.Use the&
symbol to change that result.Selecting all the shapes except the pink ones
This task requires anegation functional pseudo class, where elements must nothave the specified selector.
Without nesting, CSS today:
.demo:not(.pink){opacity:.25;filter:blur(25px);}
With nesting, here are two valid ways:
.demo{:not(.pink){opacity:.25;filter:blur(25px);}}
or
.demo{ &:not(.pink){opacity:.25;filter:blur(25px);}}
The result, all the shapes that aren't pink are hidden inside.demo
:

Precision and flexibility with&
Say you wanted to target.demo
with the:not()
selector.&
is required forthat:
.demo{&:not(){...}}
This compounds.demo
and:not()
to.demo:not()
, as opposed to the previousexample which needed.demo :not()
. This reminder is made very important whenwanting to nest a:hover
interaction.
.demo{&:hover{/* .demo:hover */}:hover{/* .demo :hover */}}
More nesting examples
TheCSS specification for nesting ispacked with more examples. If you're looking to learn more about the syntaxthrough examples, it covers a wide range of valid and invalid examples.
The next few examples will briefly introduce a CSS nesting feature, to help youunderstand the breadth of capabilities it introduces.
Nesting @media
It can be very distracting to move to a different area of the stylesheet to findmedia query conditions that modify a selector and its styles. That distractionis gone with the ability to nest the conditions right inside the context.
For syntax convenience, if the nested media query is only modifying the stylesfor the current selector context, then a minimal syntax can be used.
.card{font-size:1rem;@media(width>=1024px){font-size:1.25rem;}}
Using&
explicitly can also be used:
.card{font-size:1rem;@media(width>=1024px){&.large{font-size:1.25rem;}}}
This example shows the expanded syntax with&
, while also targeting.large
cards to demonstrate additional nesting features continue working.
Learn more aboutnesting @rules.
Nesting anywhere
All examples up to this point have continued or appended to a previous context.You can completely change or rearrange the context if needed.
.card{.featured &{/* .featured .card */}}
The&
symbol represents a reference to a selector object (not a string) andcan be placed anywhere in a nested selector. It can even be placed multipletimes:
.card{.featured & & &{/* .featured .card .card .card */}}
While this example is a bit useless looking, there are certainly scenarios wherebeing able to repeat a selector context is handy.
Invalid nesting examples
There are a few nesting syntax scenarios that are invalid and may surprise youif you've been nesting in preprocessors.
Nesting and concatenation
Many CSS class naming conventions count on nesting being able to concatenate orappend selectors as if they were strings. This does not work in CSS nesting asthe selectors are not strings, they're object references.
.card{&--header{/* is not equal to ".card--header" */}}
A more in depth explanation can be found inthe spec.
Tricky nesting example
Nesting within selector lists and:is()
Consider the following nesting CSS block:
.one,#two{.three{/* some styles */}}
This is the first example that begins with aselector list and then continues to nest further. Previous examples had only ended with a selector list. There's nothing invalid in this nesting example, but there is a potentially tricky implementation detail about nesting inside selector lists, especially those which include an ID selector.
In order for the intent of the nesting to work, any selector list that isn't the inner most nesting, will be wrapped with:is()
by the browser. This wrapping maintains the grouping of the selector list within any authored contexts. The side effect of this grouping,:is(.one, #two)
, is that it adopts the specificity of the highest score within the selectors within the parenthesis. This is how:is()
alwaysworks, but may be a surprise when using nesting syntax because it's not exactly what was authored. The trick summarized; nesting with IDs and selector lists can lead to very high specificity selectors.
To clearly recap the tricky example, the previous nesting block will be applied to the document as this:
:is(.one,#two).three{/* some styles */}
Keep an eye out or teach your linters to warn when nesting inside a selector list that's using an ID selector, the specificity of all nesting within that selector list will be high.
Mixing nesting and declarations
Consider the following nesting CSS block:
.card{color:green; &{color:blue;}color:red;}
The color of.card
elements will beblue
.
Any intermixed style declarations are hoisted to the top, as if they wereauthored before any nesting occurred. More details can be found inthe spec.
There are ways around it. The following wraps the three color styles in&
, whichmaintains the cascade order as the author may have intended. The color of.card
elements will be red.
.card{color:green; &{color:blue;} &{color:red;}}
In fact, it's good practice to wrap any styles that follow nesting with an&
.
.card{color:green;@media(prefers-color-scheme:dark){color:lightgreen;} &{aspect-ratio:4/3;}}
Feature detection
There are two great ways to feature detect CSS nesting: use nesting or use@supports
to check for nesting selector parsing capability.
Using nesting:
html{.has-nesting{display:block;}.no-nesting{display:none;}}
Using@supports
:
@supports(selector(&)){/* nesting parsing available */}
My colleagueBramus has agreat Codepen showing this strategy.
Debugging with Chrome DevTools
Current support in DevTools for nesting is minimal. Currently you will findstyles are represented in the Styles pane as expected, but tracing the nestingand its full selector context is not yet supported. We have design and plans tomake this transparent and clear.
Chrome 113 plans to have additional support for CSS nesting. Stay tuned.
The future
CSS Nesting is only at version 1.Version 2 will introduce more syntactic sugar and potentially fewer rules tomemorize. There's a lot of demand for the parsing of nesting to not be limitedor have tricky moments.
Nesting is a big enhancement to the CSS language. It has authoring implicationsto almost every architectural aspect of CSS. This big impact needs to be deeplyexplored and understood before version 2 can effectively be specified.
As a final thought,here's a demothat uses@scope
, nesting, and@layer
all together. It's all very exciting!
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2023-03-08 UTC.