CSS Nesting (Streamlining Selectors)
CSS Nesting is a modern feature that allows developers to embed one style rule within another. This capability, long a hallmark of CSS preprocessors like Sass, is now natively supported in standard CSS.
Nesting helps keep related styles grouped together, dramatically improving the readability, organization, and maintainability of your component-based CSS.
1. The Need for Nesting
Without nesting, styling components and their variations requires long, repetitive selector chains:
/* Non-Nested (Repetitive) */
.card {
border: 1px solid #ccc;
padding: 1rem;
}
.card .card-title {
font-size: 1.5rem;
}
.card:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
With native CSS Nesting, you can structure your CSS to visually match the HTML structure:
/* Nested (Organized) */
.card {
border: 1px solid #ccc;
padding: 1rem;
/* Nesting the child element */
.card-title {
font-size: 1.5rem;
}
/* Nesting the state/pseudo-class */
&:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
}
2. The Ampersand Selector (&)
The ampersand symbol (&) is the core mechanism of CSS Nesting. It represents the parent selector at the current nesting level.
A. Pseudo-classes and Pseudo-elements
The & is mandatory when nesting pseudo-classes (:hover, :focus) or pseudo-elements (::before, ::after) to join them directly to the parent selector.
button {
background-color: blue;
/* Correct: &:hover becomes 'button:hover' */
&:hover {
background-color: darkblue;
}
/* Correct: &:after becomes 'button::after' */
&::after {
content: " >>";
}
}
B. Nesting Class Selectors
When nesting other class selectors, the & is optional, but often used for clarity, especially in BEM-like patterns.
.block {
padding: 10px;
/* Becomes '.block .element' (descendant selector) */
.element {
font-weight: bold;
}
/* Becomes '.block.modifier' (chained selector for variants) */
&.modifier {
background-color: lightgray;
}
}
C. Element Selectors (The Important Rule)
When nesting a plain HTML tag selector (e.g., h1, p, a), you MUST use the & prefix for the selector to work as a descendant.
& RuleNesting simple element selectors like h1 or p without the & is currently parsed as a descendant combinator but can lead to confusion and parsing ambiguity. To ensure correct behavior as a descendant selector (.parent p), always prefix it with the & or use a space:
.header {
/* GOOD: Explicitly tells the browser to look for a nested 'h1' */
& h1 {
font-size: 2rem;
}
/* GOOD: Same as above (space is implicit descendant) */
h1 {
font-size: 2rem;
}
/* BAD: Currently works, but is discouraged and confusing */
/* p { color: red; } */
}
The safest practice is to use the & for pseudo-selectors and classes, and allow element selectors to function as implicit descendants.
3. Nesting Media Queries
You can also nest media queries inside a selector block. This is incredibly useful for ensuring that all responsiveness for a component is contained in one declaration block.
.post-card {
display: block; /* Default mobile layout */
width: 100%;
/* The entire component's desktop layout change is contained here */
@media (min-width: 768px) {
display: flex; /* Switch to horizontal layout on desktop */
padding: 20px;
/* Child element style change within the media query */
.post-image {
width: 40%;
}
}
}
Interactive CSS Nesting Demo
This demo uses native CSS Nesting to style a Card component, including a nested title and a hover effect, all within the main .nested-card block.