Writing SCSS with BEM

Day to day, I read and write a quite a lot of SCSS. I often fol­low BEM’s guidelines whilst writ­ing it. So nat­ur­ally over time I’ve developed opin­ions on what I think con­cise, clear but also main­tain­able BEM + SCSS looks like.

The Ideal Example #

So below is how, in an ideal world, I would write SCSS:

.block {
  &__element {
    &:hover {
      ...
    }

    @media screen and (min-width: 768px) {
      ...
    }

    &--modifier {
      &:hover {
        ...
      }

      @media screen and (min-width: 768px) {
        ...
      }
    }
  }

  &__element-sibling {
    ...
  }
}

There’s a few things going on above so let’s break it down.

Use the & ali­as to keep BEM con­cise #

So one of the main nuis­ances with BEM is it’s tend­ancy to pro­duce looooong class names e.g .navigation-bar__hero-title--highlighted. So to rem­edy this in your stylesheets, I find it a good idea to break up the name through a com­bin­a­tion of nest­ing and the SCSS & alias.

For those unfa­mil­i­ar, the & ali­as is short­hand for the par­ent select­or that the & is nes­ted in. For example…

.button {
  &__icon {
    ...
  }
}

…when com­piled down to CSS will be .button__icon. A lot less duplic­a­tion with all the safety and nice­ness of BEM.

It also has the added bonus that styles that use & get com­piled into single class styles i.e. .button__icon vs. .button .button__icon. This is good because it keeps the spe­cificity low and the styles open to being overriden.

How­ever, the & ali­as can be pain­ful. Ima­gine the scen­ario where a set of styles were mis­be­hav­ing. A developer would open up the browser dev tools, find the offend­ing class name and do a file search for it in their code­base. If the select­or is broken up using & ali­ases then search­ing for .button__icon like in the example above won’t pro­duce any results.

This issue can be ale­vi­ated how­ever by fol­low­ing some simple rules…

Use nest­ing to reflect the BEM hier­archy #

So I usu­ally have three levels of style nesting:

Each cor­res­ponds to levels of the BEM hier­archy. So it would look some­thing like:

.block {
  &__element {
    &--modifier {
      ...
    }
  }
}

Nes­ted inside each of these levels may be media quer­ies and pseudo-class rules, bring­ing the max level of nest­ing to four (e.g. a media query in a mod­i­fi­er class).

If your stylesheets are con­sist­ently struc­tured like this, then file search­ing for styles is easy.

For example, if you were try­ing to debug styles for .button__icon you could search for &__icon. Or if there are mul­tiple occur­rences of that, search for .button and then loc­ate the &__icon nes­ted inside of it.

Don’t abuse nest­ing #

Going from CSS to SCSS, you can get car­ried away with the cool fea­tures SCSS gives you. Over-nest­ing of styles is a par­tic­u­lar head­ache of mine.

.class-1 {
  .class-2 {
    .class-3 {
      .class-4 {
        ...
      }
    }
  }
}

In this small example, it’s just about read­able. But ima­gine a stylesheet that’s hun­dreds of lines long. If you need to add a style, it gets harder and harder to fig­ure out what level of the nest­ing you’re adding to.

Also, if you’re not using the & ali­as, SCSS will com­pile the above styles to:

.class-1 .class-2 .class-3 .class-4 {
  ...
}

Each level of nest­ing bumps up the spe­cificity of the styles and makes them harder and harder to override. 👎

Don’t nest sim­il­arly named classes #

Nest­ing blocks/​elements/​modifiers inside sim­il­arly named classes is a bit of a pet peeve of mine, it makes the nes­ted classes much harder to search for. Take the fol­low­ing example:

Do
.block {
  // .block__element
  &__element {
    ...
  }

  // .block__element-two
  &__element-two {
    ...
  }
}
Don't
.block {
  // .block__element
  &__element {
    // .block__element-two
    &-two {
      ...
    }
  }
}

By avoid­ing nest­ing .block__element-two inside .block__element we make both ele­ments easy to search for and, in my opin­ion, we make the code more scannable.

For scop­ing, use mod­i­fi­ers over nest­ing #

In addi­tion, nest­ing is often used to​“scope” styles to spe­cif­ic con­texts. But if you’re using BEM, you don’t need to worry about that. Pre­fix­ing the block name to all classes does the scop­ing for you.

If you need to slightly tweak a block on a spe­cif­ic page, I find it bet­ter to use mod­i­fi­er classes to adapt the block instead of chan­ging the styles inside a page-spe­­ci­f­ic class.

One block per file #

I find hav­ing one SCSS file per block a nice rule of thumb. It makes each block dis­cov­er­able via file explorers and keeps each file small and concise.

Sum­mary #