Two tips for success with your BEM CSS

posted in: Uncategorized | 0

CSS is easy to understand, but frustrating to use. Especially on large projects. With a growing code base and multiple developers (i.e., the real world), cascading and specificity quickly cause complications and unexpected results. My two favorite solutions to the problems of cascading styles and specificity include CSS Modules and BEM.

BEM—eye roll—seems complicated and wordy, but it is a convention that provides name-spacing and flattening of specificity. These are two very worthy goals that lead to predictability and maintainability.

I had some fundamental misunderstandings when I first started working with BEM, so I want to clear those up. I think it will help others learn to use BEM faster and better.

BEM is not nesting!

This is the most fundamental misunderstanding when first encountering BEM. BEM—block__element–modifier—sounds (and even looks) like a series of nested elements, like SCSS or atomic design with an element inside of a block and modifier inside of an element. But it is not. Wipe that nested model out of your mind. In fact, as we’ll see below, you would never use a class by itself that looked like bock__element--modifier.

Elements and modifiers are two separate things with two separate purposes (not smaller versions of the same thing). The following two revelations have been the light bulb for me that has helped me use BEM consistently and effortlessly.

Tip 1. Elements can be any level of descendant

The block is the namespace, the container. Simple. Elements are independent things inside of that namespace, whether a direct descendant (child) or a descendant of a descendant. The __ notation does not mean child, it means descendant. Try it, you’ll like it.

For example, imagine a hero banner with an icon and an inner area that contains text. Inside the inner area is a title and a subtitle. Using BEM, your SCSS could look like this:

.hero {
  &__icon {}
  &__inner{}
  &__title {}
  &__subtitle {}
}

The title and subtitle are not nested inside of inner in the SCSS even though they are nested in the HTML, and that is okay. They are equally independent elements of the hero. The elements inside the hero are flat inside of their block class.

But what if you have a really complicated component? Is EVERYTHING inside it an element?

Not necessarily. If it makes sense in your component to put another block inside of a block, that is fine. You can put the block inside, or, introduce another block name as a class on one of the containing block’s descendants.

For example, if you have a specific card layout inside the inner area of your hero, hero__inner, you could introduce a card block style like this:

<div class="hero__inner card">
   <div class="card__title"></div>
</div>

Then the card component inside the hero__inner becomes its own block and all its inner elements can be styled starting with card__. The .card styles can be in their own file, card.scss, so you know where to find them.

This convention makes it easy to understand what the CSS applies to, where it is used in your code, and where to find it in your directory.

So what are modifiers? Modifiers are NOT descendants. They are NOT inner parts of elements. They are versions of blocks or elements. Things that are --active or --dark or --hidden. And that leads to the second fundamental rule:

Tip 2. Modifiers must always be used with their base class

Modifiers are just that, modifiers. Unlike elements, they are not independent. They are never used alone. They always take a base class and modify it.

Take a scenario where you want to use your hero block on a bunch of pages with the same exact styles, but with different background images. This is a perfect use case for a modifier. Your code above would then look like this:

.hero {
  background-image: url(`default.jpg`);
  // all your standard background styles here

  &--about {
    background-image: url('about.png');
  }
  &--careers {
    background-image: url('careers.png');
  }
  &__icon {} 
  &__inner{} 
  &__title {} 
  &__subtitle {} 
}

On your careers page, your HTML would be

<div class="hero hero--careers">

The class is the base class plus the appropriate modifier that adds the appropriate background image to the hero. The base class, hero, defines all the default hero styles including the default background image styles. The modifiers in this case modify the background image. But the modifier could modify color or border or visibility or whatever needs to change in each new context.

Notice also that the modifier does not only attach to an element. It can modify a block or an element, but it always has to be used with one or the other, and never alone.

You should have no need for double elements or double modifiers like block__element__sub-element--modifier--sub-modifier. Ick. At most, you’ll use block__element block__element--modifier. Maybe this technique should be called BE BEM or BE BEm or B(E) B(E)m?

These simple rules can clean up your code and make it more accessible to other developers (as well as future you). With the correct understanding of blocks and elements and their helper modifiers, you can write cleaner, more maintainable code.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *