Srihari Sriraman

Read more by Srihari here

You probably shouldn't be nesting your CSS

TL;DR: Don’t nest CSS. Nest class names instead. This is one of the most useful take-aways from SMACSS. Follow this, and it will change the way you write scss for the better.

With the coming of sass, we have all seen how writing css has gotten easier. We love writing css that is similar to our html. The following would seem natural to us:

HTML for a component
1
2
3
4
5
6
7
8
9
<div class="my-component">
  <header></header>
  <div class="some-section">
    <header></header>
    <p class="description">
      <span class="important"></span>
    </p>
  </div>
</div>
Styling the component (the wrong way)
1
2
3
4
5
6
7
8
9
div.my-component {
  header {}
  .some-section {
    header {}
    p {
      .important {}
    }
  }
}

This gives us the comfort of nesting css the same way we nest html. It gives us context that some-section rests inside my-component, but nothing more. And, this gets convoluted quickly. if I had to override the style for this component elsewhere, I’d have to do something like:

Overriding the style for .important
1
.my-component .some-section p .important {}

The correct way:

Add the context, name of component/module in the class attribute:

HTML for a component
1
2
3
4
5
6
7
8
9
<div class="my-component">
  <header class="my-component-header"></header>
  <div class="my-component-section">
    <header class="my-component-section-header"></header>
    <p class="my-component-section-description">
      <span class="my-component-section-important"></span>
    </p>
  </div>
</div>
Styling the component (the correct way)
1
2
3
4
5
6
.my-component {}
.my-component-header {}
.my-component-section {}
.my-component-section-header {}
.my-component-section-description {}
.my-component-section-important {}

What does this give us?

  • All the context that we got in nesting css. Except that the nesting is in the name instead of nested braces that are hard to read.
  • CSS with minimum specificity so that it is easy to override. For the purpose of subclassing modules, it is preferable to nest the styling by exactly one level. See exceptions below.
  • Independence from structure, so we can move our components around without having to move css around. For this purpose, it is also good to stay away from element selectors.
  • Control over cascading, that you thought was only possible with nesting. The nesting in class names gives a unique name to your selector that is quite hard to override accidentally with cascading.
  • The answer to “Where is the CSS for this?”. Since the selectors have almost a one to one mapping with the class attributes, you just have to file-search for them now.
  • Speed. See how this helped github speed up their diff pages.

Conclusion:

Don’t nest CSS. You could start off with the inception rule, but I strongly suggest you stick to zero nesting levels (see exceptions below).

Exceptions:

  • When you are writing modules that you will subclass, it is necessary to nest (by one level) the styling under the module’s selector so that you can keep the defaults and override only the differences.
  • When overriding base rules, one usually has to provide enough specificity to override an element selector, say. In these cases, nesting (by one level) is ok.