Using BEM in the Wild


BEM can get out of control if you’re not careful. On the first project I used BEM, I handcrafted this artisanal class name: .progress__bar__question-count__current-number.

Yup. That’s four levels deep. I’m not proud of this.

The goal of this article is to make sure another .progress__bar__question-count__current-number never gets written. Before we dive in, if you’re not familiar with the BEM naming convention, head over to B is for Block: An Intro to the BEM Naming Convention. Don’t worry, I’ll wait until you’re done.

Ready? Good. Here we go!

It’s BEM, not BEEEEM

Be as descriptive as you need to be with your BEM class names to avoid duplication and confusion. Sure, my .progress__bar__question-count__current-number class lets me know that current-number is nested 4 levels deep in the HTML, but is that worth the verbosity?

Nope.

It means more changes to make in your CSS when you modify the HTML. Rather than duplicate your HTML structure, be descriptive and unique.

When I refactor, .progress__bar__question-count__current-number will become .progress-bar__current-number.

Ah. Much better.

“The best is the enemy of the good.” – Voltaire

I can get stuck in a pattern of trying to find the perfect solution rather than an easy one that accomplishes the task. As the saying goes, “Don’t let perfect be the enemy of good.” That’s when .progress__bar__question-count__current-number rears its ugly head.

Remember, BEM is a convention to make your code easier to maintain. If it’s not making your code easier to maintain, modify it. BEM is a tool for you to use, not vice-versa.

If a Block is Within Another Block, Mix It

One of the great things about BEM is the flat class structure. You don’t have to nest anything in SASS or use multiple class names to win a specificity battle.

That’s great… until a block is nested inside another block. Let’s say you have a .card block that has a .list and a .button inside it. What do you do? Do you duplicate the entire block again with the block name prefixed? That’s the only way to keep it 100% perfect and flat. So, should we do this?

<article class='card'>
  <div class='card__header'>
    <h2 class='card__title'>B is for Block: How to BEM</h2>
  </div>
  <div class='card__content'>
    <ol class='list card__list'>
      <li class='list__item card__list__item'>
        Describe the Main Block with a word or two.
      </li>
    </ol>
    <a class='button button--with-icon card__button card__button--button-with-icon'>
      <span class='button__text card__button__text'>
        Read More
      </span>
    </a>
  </div>
</article>

No! Don’t put BEM in your BEM. That’s what leads you down the crooked path to .progress__bar__question-count__current-number! Heed my warning. Don’t do it. Nest the components, but mix the class names, and let your specificity win out with the nested class names. Like this:

<article class='card'>
  <div class='card__header'>
    <h2 class='card__title'>B is for Block: How to BEM</h2>
  </div>
  <div class='card__content'>
    <ol class='list card__list'>
      <li class='list__item'>
        Describe the Main Block with a word or two.
      <li>
    </ol>
    <a class='button button--with-icon card__button'>
      <span class='button__text'>
        Read More
      </span>
    </a>
  </div>
</article>

Here’s the above example in a CodePen that highlights the components and displays the class names that go with it:

See the Pen BEM Syntax Visualized by Jerry Jones (@jeryj) on CodePen.

//assets.codepen.io/assets/embed/ei.js

You might encounter a time where it’s helpful to put your BEM in your BEM a little bit, but be careful with it. Remember, BEM is supposed to be helpful to you and your team. Feel free to “modify” it.

See what I did there?

Blocks Don’t Care About Other Blocks… Until They Move In

You have a .friend. They’re a good .friend, but sometimes they do things you don’t agree with. Nothing wrong with that.

You have .your-house. You like your .friend and .your-house doesn’t care about what your .friend does. They can go wherever they want. Do what they want to do.

Until your .friend gets kicked out. They need a place to stay.

Enter, .your-house. But when your .friend is living with you, they’re going to need to follow your rules. .friend has to realize that now, they’re also .your-house__friend.

// home sweet home!
.your-house {
    laundry: clean;
    dishes: clean;
}

// do what you want! be you!
.friend {
    laundry: dirty;
    dishes: dirty;
    goes-out: tons;
    pays-rent: nope;
    demeanor: nice;
    fun: yes;
}

// Uh oh. Gotta set some rules while
// they're living in your house
.your-house__friend {
    laundry: clean;
    dishes: clean;
    pays-rent: yes;
}

Blocks don’t care about other blocks. That’s what makes them maintainable and predictable. When you put a block inside another block, the parent block is the one that cares. .friend doesn’t care that it’s in .your-house. .your-house is the one that cares, so it sets the rules on .your-house__friend.

Be a good .friend and keep .your-house class names tidy.

The BEM Cheatsheet

Here’s the cheatsheet of the tips for actually using BEM.

  1. Formatting: .block__element--modifier
  2. Describe the block with a word or two. If it’s two words, separate them with just one dash or do camelCase or whatever. Doesn’t really matter. Just be consistent and document it.
  3. Describe the __element with a word or two.
  4. Add --modifiers if necessary.
  5. Avoid lots of __elements unless you can’t avoid it. For example, .card__title__link__progress__icon is a little excessive.
  6. You can mix classnames that are parts of two blocks. For example, if it’s a .button block, but it’s also a .card__button element, you can use both in the HTML.

That’s it. You should know enough to confidently use BEM and avoid common traps. You’ll still come across scenarios that you’re not sure what to do. We all do. If you have any questions or think I made a mistake, let me know at @juryjowns.


2 responses to “Using BEM in the Wild”

  1. Your skill at explaining CSS to noobs is prodigious. I am enlightened! Love the .friend and the .your-house analogy.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: