&
Lets you write rules inside other rules, like in Sass. The & sign stands for the parent rule’s selector.
Example
#.btn {
padding: 8px 14px;
border: 0;
border-radius: 8px;
background: #7c3aed;
color: #fff;
&:hover {
background: #6d28d9;
}
&.ghost {
background: transparent;
outline: 1px solid #7c3aed;
}
.icon {
margin-right: 6px;
}
}<style>button { font: inherit; cursor: pointer; }</style>
<div style="display: flex; gap: 8px;">
<button class="btn" type="button"><span class="icon">▶</span>Start</button>
<button class="btn ghost" type="button">Cancel</button>
</div>Definition and usage
#Native CSS nesting lets you place one rule inside another. A nested rule applies to elements inside the parent, so .card { p { … } } works like .card p { … }. You keep a component’s code in one block and don’t repeat the class name over and over.
The & sign stands for the parent rule’s selector. You need it when a selector should attach to the parent with no space: &:hover is hovering over the element itself, &.active is the element with an extra class, and &::before is its pseudo-element. Without &, the browser treats a nested selector as a descendant. & can also come at the end: .dark & { … } changes an element’s style when it sits inside .dark.
Inside a rule you can also place @media and @supports, and the declarations written in them apply directly to the current selector. This is handy for responsive styles: everything related to a button lives in one place.
It differs from Sass in the details. The browser doesn’t glue name fragments together, so &__title won’t build the class .card__title. The & selector also behaves like :is(): when the parent is the list #logo, .brand, a nested rule picks up the weight of the strongest selector on that list.
Syntax
#parent {
property: value;
child { … }
&:hover { … }
&.class { … }
.context & { … }
}Notation variants
#without &
A nested selector without&means a descendant, just like.demo span. The labels in every card change color.- Hover over any card.
&attaches the pseudo-class to the card itself, with no space. - A card that also has the class
active. Plain.activeinside the rule would look for a descendant with that class. &at the end reverses the direction: the card gets the style when it lies inside.promo.- An
@mediarule inside the block applies directly to.demo. The preview is wider than 300px, so the cards are blue.
Notation variants in practice
#span
& means a descendant, just like .demo span. The labels in every card change color..demo {
span { color: #fbbf24; }
}&:hover
& attaches the pseudo-class to the card itself, with no space..demo {
&:hover { background: #7c3aed; }
}&.active
active. Plain .active inside the rule would look for a descendant with that class..demo {
&.active { background: #7c3aed; }
}.promo &
& at the end reverses the direction: the card gets the style when it lies inside .promo..demo {
.promo & { background: #7c3aed; }
}@media (min-width: 300px)
@media rule inside the block applies directly to .demo. The preview is wider than 300px, so the cards are blue..demo {
@media (min-width: 300px) {
background: #0284c7;
}
}More examples
#.grid {
display: grid;
gap: 8px;
@media (min-width: 560px) {
grid-template-columns: repeat(3, 1fr);
}
}<div class="grid">
<div class="box">HTML</div>
<div class="box">CSS</div>
<div class="box">JS</div>
</div>On a wide screen the items sit in three columns, on a phone one below another. The grid’s entire behavior lives in a single block.
Browser support
#Widely available · since 2023
Works in all modern browsers, phones included. You can use it without worry.
- Chrome
- Edge
- Firefox
- Safari
Good practices
#- Don’t nest deeper than two or three levels. Every level means a longer selector and higher specificity, exactly like with a hand-written chain.
- Always write pseudo-classes and pseudo-elements with
&:&:hover,&::after. Plain:hoverinside a rule means "any descendant under the cursor". - If the site needs to work in browsers from before the end of 2023, stick with a preprocessor (Sass, PostCSS) that compiles nesting down to plain CSS.
Related entries
#- A BA space between selectors selects B elements anywhere inside element A, at any depth.
- :hoverMatches the element the mouse cursor is currently over. The basis of hover effects on buttons, links, and cards.
- :is()Matches an element against any selector in a list. Shortens long, repetitive selectors into a single notation.
- SpecificityA selector’s weight, which decides which rule wins when several rules set the same property on the same element.
- .classSelects elements that have the given class in their class attribute. The most commonly used selector for styling components.
Spotted a mistake or missing an example? Write to us.