CSS nesting
Nesting means writing rules for child elements inside the parent's rule. Since 2023 it has been part of standard CSS and works in new browsers without a build step. postcss-preset-env unwraps it into ordinary flat selectors if your Browserslist list contains browsers without support. With the defaults list it does.
Nested rules
There is nothing extra to install — nesting is part of postcss-preset-env from the previous lesson. Write the post card styles in styles/main.css:
/* styles/main.css */
.post-card {
padding: 16px;
h2 {
margin: 0;
}
&:hover {
border-color: #2563eb;
}
}After npx postcss styles/main.css -o css/main.css:
.post-card {
padding: 16px;
}
.post-card h2 {
margin: 0;
}
.post-card:hover {
border-color: #2563eb;
}The nested h2 became the descendant selector .post-card h2. The & sign stands for the parent selector itself, so &:hover became .post-card:hover. The extra indentation in the unwrapped rules is a quirk of the plugin and does not bother browsers.
& in another position
& does not have to come first. This is how you style the card inside another block:
/* styles/main.css */
.post-card {
padding: 16px;
.is-featured & {
border-width: 2px;
}
@media (min-width: 768px) {
padding: 32px;
}
}.post-card {
padding: 16px;
}
.is-featured .post-card {
border-width: 2px;
}
@media (min-width: 768px) {
.post-card {
padding: 32px;
}
}.is-featured & produced .is-featured .post-card, and the media query was moved outside with the selector repeated.
A separate plugin
If you do not need the rest of postcss-preset-env, add only nesting — the postcss-nesting plugin:
npm install --save-dev postcss-nesting// postcss.config.js
import postcssNesting from 'postcss-nesting';
export default {
plugins: [postcssNesting()],
};It always unwraps nesting, without looking at the browser list.
CSS nesting and Sass
| CSS Nesting | Sass | |
|---|---|---|
| Works without a build | Yes, in new browsers | No |
Joining names like &__title | No | Yes |
| Nested media queries | Yes | Yes |
Common mistake
Bringing BEM name joining over from Sass:
/* styles/main.css */
.post-card {
&__title {
font-size: 20px;
}
}In standard CSS, & is a whole selector, not a piece of text. The plugin outputs the meaningless __title.post-card, and the style never applies. Write such classes as separate rules: .post-card__title.