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.
- Formatting:
.block__element--modifier
- 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.
- Describe the
__element
with a word or two. - Add
--modifiers
if necessary. - Avoid lots of __elements unless you can’t avoid it. For example,
.card__title__link__progress__icon
is a little excessive. - 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”
Your skill at explaining CSS to noobs is prodigious. I am enlightened! Love the .friend and the .your-house analogy.
LikeLike
Ha! Thanks 🙂 Your willingness to dive into a subject is pretty impressive!
LikeLike