Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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 NestingSass
Works without a buildYes, in new browsersNo
Joining names like &__titleNoYes
Nested media queriesYesYes

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.

Thanks for reading!

Donate to the site — we work hard for you.