Skip to main content

Of Mice and BEM: Getting Past Common Problems With CSS Organization

02-11-19 Philip Zastrow

Philip addresses four common misconceptions about BEM and explains how and why the CSS naming convention of Block Element Modifier helps solve organizational thinking around class names.

The CSS naming convention of Block, Element, Modifier, or BEM, can be a tough concept to grasp. The fundamentals of this naming convention are fairly straightforward, but a lot gets lost in translation as developers begin implementing the tool. A couple of years ago, Nathan Rambeck wrote a fantastic article in an effort to curb common implementation mistakes called “BEM by Example,” which gets into the depths of practical uses of the naming convention through code demos. I think it is a great article, and I consider it a precursor to what follows. I want to turn the focus here to common hang-ups and misconceptions I’ve observed and also explain how using BEM has formed my thinking and approach to writing CSS.

I have been practicing and teaching BEM for more than two years now. I was at first an ardent critic of the convention, as I found the syntax unsightly, namely the double underscores and double dashes. While my opinion hasn’t changed there—that’s the designer in me—the problems BEM solves for me in my day-to-day CSS writing far outweigh my internal syntactical squabbles. For me, BEM makes naming easier, as it focuses my thinking to ask questions about the elements and how they relate to corresponding elements. Join me as I reexamine my own observations and evolution of using BEM in my work here at Sparkbox.

Some Common BEM Hang-Ups

There are a few misunderstandings that can cause a hang-up for developers implementing BEM in their projects. The most common problems stem from understanding how the HTML and CSS of BEM relate. The confusion is often rooted in logic, but really the relationship between HTML and CSS with BEM needs to be viewed rather abstractly. The primary point of the BEM structure is to provide unique class names to style HTML elements. But often the concept of BEM is taken to an nth degree that exceeds the intentions of the method, resulting in improper implementation and, at times, frustration.

Hang-Up #1: BEM is an HTML Mirror

I have been teaching BEM for the last two years through the Modern CSS workshop and our apprenticeship program. Even among my fellow Sparkboxers there is one common misconception that keeps coming up in regards to BEM: that it is a mirror that reflects the HTML. Many BEM beginners start by seeing each HTML tag as a unique class that fits into this new naming convention with which they are working. This leads to HTML/CSS classes that look like this:

<section class="blog-post">
  <header class="blog-post__header">
    <h1 class="blog-post__header__title">...</h1>
  </header>
  <article class="blog-post__body">
    ...
  </article>
</section>

It is very easy to see how that perception makes its way into the approach, but that is not the intention of the structure. There should be only one, and no more than one, Element level name per class. The same goes for Modifier level names. Instead of having a class name of blog-post__header__title, the appropriate BEM structure should provide blog-post__title as the class name. The relationship of these elements is defined only by their Block section of the class name, not their HTML ancestry. One way I have found it helpful to think about this relationship of BEM classes is to think of the Block level as a “family name” or last name.

Let’s take BEM naming and use it as the impetus behind providing names within a family, looking only at first names and last names. We’ll call our example family the Hoverstates and we’ll be looking at the family tree that consists of Grace, her daughter Maddie, Maddie’s sons Sam and Lee, and Grace’s brother Ed, along with Ed’s daughter Alexis. If we were to pair these family relationships with HTML and a BEM naming convention, it would look like this:

<div class="hoverstates">
  <div class="hoverstates__grace">
    <div class="hoverstates__maddie">
      <div class="hoverstates__sam">...</div>
      <div class="hoverstates__lee">...</div>
    </div>
  </div>
  <div class="hoverstates__ed">
    <div class="hoverstates__alexis">...</div>
  </div>
</div>

Naming every ancestral deviation isn’t common for most modern Americans, so this may feel different to you. From the example, Sam’s class name isn’t hoverstates__grace__maddie__sam. Sam is a Hoverstate and that is all that really matters. The relationship to all the other Elements in a BEM Block is that they are a part of the same family.

To put it another way, the Block isn’t the start of the BEM ancestry, it is the unifying factor. Additionally, the Elements aren’t defined by their ancestry; instead, they’re defined by their purpose within the Block.

Hang-Up #2: When to Define a Block, an Element, and a Modifier

The second most common hang-up I see is deciding the right situation to create a Block, followed by an Element, and then Modifier. Sometimes the BEM family becomes so extensive that following the relationships is nearly impossible. For starters, keeping your BEM family small will help with tracking these relationships. However, if you are seeing your BEM families become quite large, it may make sense to break down things into smaller units.

For example, if you are creating a site header component, a group of elements that work as a cohesive feature that has a logo, search form, primary navigation, and secondary navigation, it will be easier to manage four or five unique BEM families than a singular large family.

Instead of creating a singular component, break it down into unique components with their own connected BEM family for each component. Then, have an overarching header component that brings together these components. By family, I am referring to the number of Elements, Modifiers, and Element Modifiers the Block contains. There isn’t an ideal number, but generally I have seen that the more the Block contains, the harder it is to manage. Like the first hang-up as well, not every HTML element in the HTML needs to be represented as a BEM class or even have a class for that matter. It is okay to use a div or other HTML element without styling it, and an element should only have a BEM class if it is being styled—the exception being if it is the Block element.

Thus, create an Element class for each HTML element in your Block that needs to be styled. If you are creating an Element class that has only a single property, then consider if a utility class makes more sense. Modifiers, on the other hand, are really only there for very unique, usually state-related, situations. Modifiers are for when a Block or Element have variations or change state, and typically those Modifier classes are only changing a couple of properties. Modifier classes are the only instance of adding additional classes to a Block or Element class HTML element. Be judicious with Modifier classes, but don’t be afraid to have many on a single HTML element.

Hang-Up #3: When to Redefine a Block

At Sparkbox, we highly encourage refactoring our code, and CSS is no different. The purpose behind a component can change over the course of a project as similarities are realized between different parts of the website. Renaming a Block level should be a common occurrence throughout the course of development. Nathan once again has written a fantastic article on this topic, “Why You Need to Refactor Your CSS.”

If you are using Sass to write your CSS, then a terrific method exists to make name changing for your compiled CSS very easy. That method is a staple Sass feature called the Referencing Parent Selector, signified by the &. I wrote a love letter about this particular feature some years ago, and since then have learned that it is even more extensible than I originally described. Since BEM utilizes a methodology of repetition in class naming, we can use the & to reference those relationships, as so:

.block {
  // styles for .block
  &__element {
    // styles for .block__element
    &--modifier {
      // styles for .block__element--modifier
    }
  }
  &--modifier {
    // styles for .block--modifier
  }
}

This output replaces each instance of & with the parent of the nested selector block. To rename a whole family of BEM selectors, change the name of the Block level class name. The harder part will be updating your HTML template. This type of organization helps keep related selectors well defined. To take this further, use this in combination with ITCSS to organize your Sass partials in a meaningful way.

Hang-Up #4: Blocks in Blocks

Lastly, another very common BEM misconception is that everything within the HTML Block element must be represented with an Element level class name. Sometimes that even means providing an HTML element with two classes, one that connects the element to its ancestral Block class as well as a class that defines a new Block.

<div class="block">
  <div class="block__element-one">...</div>
  <div class="block__element-two new-block">
    <div class="new-block__element">...</div>
  </div>
</div>

Here is the problem with this approach. There are two prime classes that will be used here and will very likely live in two different partials. This is a recipe for unintended cascade overwriting. First, a Block can effectively live within another block and doesn’t need to have a secondary class explaining that relationship (see Hang-Up #1). Theoretically, each Block should be able to live independently. Instead, if there is a connection necessary, consider using a wrapper for the new block, such as:

<div class="block">
  <div class="block__element-one">...</div>
  <div class="block__new-block">
    <div class="new-block">
      <div class="new-block__element">...</div>
    </div>
  </div>
</div>

This provides an extra HTML element that can provide styles for the instance that the .new-block element is inside the .block element. Secondly, BEM classes are intended to provide unique class names to singular elements. When using BEM class names the only additional class names on that element should be Modifier classes, never Block nor Element level classes. While yes, it is possible to put various Block and Element classes on a single element, those classes can quickly begin to overwrite one another, and I highly discourage the practice.

How BEM Helps Me Write CSS

As I mentioned at the beginning of this article, I was very resistant to adopting BEM. But since seeing that it was becoming commonplace and adopting it as my own, I have learned so much from this methodology. This has led Melissa and me to write the CSS style guide portion of the Sparkbox Standard. BEM has also helped me create a rubric for CSS class naming, making it almost effortless. I have changed my perspective on adding extra HTML, and instead see it as a boon for organization. Lastly, I’ve been surprised to find how well BEM lives alongside other approaches and decreases the likelihood of cascade collisions.

BEM Helps Make CSS Naming Effortless

I really think I have found the necessary tools for making quick decisions when it comes to creating class names. Naming in development is notoriously difficult, but BEM has helped me formulate a structure for naming classes that has helped me stay away from names that are cryptic or abstract. I want to share my mental rubric for CSS class names as inspired by working with the BEM convention of naming.

Human-Comprehensible Class Names

I feel like this goes without saying: class names should be easily comprehensible to humans. The thing is, though, I see a lot of common practices that I find difficult to decipher. The biggest offender is single character naming. Using a single letter such as u, l, or c to provide context or description in a class name is as useful as a randomly generated sequence of characters. Give yourself the freedom to be a little verbose for the sake of humans’ sanity. Future you may thank you.

Adequate, Not Overly Descriptive, Class Names

On the reverse side of human-comprehensible class names is the opposing side of no more than adequate. Once you get going with that newfound freedom to be verbose it is easy to overly describe the purpose of a class with its name. The goal is to be only adequately descriptive. When I am making a search component that shows up in a header, I typically will call that Block class .site-search, as opposed to .header-search, because hopefully I can drop the same component and style into other places, such as the footer or an aside space. If the design is intended to be different, then the .header-search may be appropriate, or perhaps more likely a modifier like .site-search--header is all that is needed.

Class Names that Use a Common Nomenclature

I use and reuse the same boring Element suffixes over and over again. This is because they are sufficiently descriptive. In my experience, using these same names repeatedly helped me develop a mental nomenclature, which shows up time after time. When utilizing the Sass Referencing Parent Selector, I have many instances of &__item, &__list, or &__link. These types of names are clear and consistent, allowing for rapid development and little time thinking about naming.

BEM Has Helped Me Understand How More HTML Can Mean Fewer Problems

In Hang-Ups #2 and 4, I discussed the observation that developers often struggle with where to place Blocks. What I have personally found in struggling through this aspect of BEM is a freedom to add extra HTML elements as needed. Prior to this, I was a hardliner on keeping my HTML as simple as possible. As I have used BEM, I have found that an extra HTML element with a specific BEM class can allow for more versatility and more legible organization of both styles and markup.

I don’t say this as a means to go hog wild with your HTML. You should still aim for keeping HTML as simple as possible. Instead, what I’ve found through BEM is the freedom to be more liberal in my usage of extra HTML elements to better break down the responsibilities of a selector block to multiple elements.

This kind of freedom, however, bears great responsibility. When adding more elements to a page, we need to make sure we are not causing layout issues and misalignment of content. To avoid this I prefer to abstract out spacing properties (margin and padding) to the outer most HTML elements that make sense. One problem I’ve seen is if each BEM element has its own padding that can cause misalignment issues. Unlike, margin, padding is spacing on the inside of the containing element. If .block has padding: 1rem and .block__element has padding: 0.5rem, then .block__element will actually be inset 1.5rem.

BEM Has Shown Me It Is Extensible and Can Coexist With Other Conventions and Frameworks

I was brought in to create a new feature for the site where you’re now reading this article, sparkbox.com. I decided the time was right to move toward using the BEM practices we had been using for a couple years on other projects. What was so fantastic was that it was truly effortless to integrate BEM into a system that did not previously use BEM. I made some instructive comments to explain this shift and did it in such a way to encourage our team to refactor the entirety of sparkbox.com to BEM.

Beyond this example, I can say I have seen BEM work alongside frameworks such as Bootstrap quite effectively. Many of these frameworks create their own naming conventions, and the verboseness of BEM is the bread and butter of its ubiquity. It is a naming convention that can truly live alongside other conventions with little to no fear of conflicting selectors. So, if you’ve been waiting to try out BEM on a new project, wait no longer. That old project you’ve been toying at for some time is ripe for some BEM-ification.

Reflection

If you’ve only given BEM a single shot and haven’t tried it since, I hope you’re able to give it a second chance. The monumental moments in web development for me have always been when I’ve had to change how I think about development. And BEM was no exception. If you’ve been using BEM for sometime on a project that precedes you, then I hope you’ve found some encouragement in changing your approach to BEM. I don’t think BEM solves all the problems of CSS at scale, but it does solve a lot of organizational thinking for me. I prefer spending my time thinking about properties, not class names. BEM provides me an avenue to make naming simple so I can focus on what I truly love about CSS, which is solving problems and styling with CSS properties.

Sparkbox’s Development Capabilities Assessment

Struggle to deliver quality software sustainably for the business? Give your development organization research-backed direction on improving practices. Simply answer a few questions to generate a customized, confidential report addressing your challenges.

Related Content

See Everything In

Want to talk about how we can work together?

Katie can help

A portrait of Vice President of Business Development, Katie Jennings.

Katie Jennings

Vice President of Business Development