Keeping the Front-End Modular with BEM

Connie Chan

There has been a lot of back-and-forth lately at thoughtbot about how to best structure our CSS class names. Inevitably, we always wind up discussing BEM with mixed opinions. Having completed a smaller greenfield project recently that used BEM naming, I can safely say I’m a convert. The organizational approach of the framework provides a great guideline on how to manage the same content that needs to be viewed in different contexts. Combined with a preprocessor, BEM makes keeping your CSS modular and object-oriented a breeze. If you’re working on a project that follows the MVC pattern, BEM fits right at home. Don’t let its syntax scare you away!

What is BEM?

To give a quick recap, BEM stands for “Block”, “Element” and “Modifier”, and is a class naming convention. Each block could be an object group or feature (for example, a search form), the elements would be its children (a search input and button), and a modifier could be one of its states (such as “disabled”, “is animating”, or “is visible”).

.search { // Block
  align-content: center;
  display: flex;

  &--is-disabled { // A Modifier for disabled state
    display: none;
  }
}

.search__input { // Block with an Element
  border: 1px #000 solid;
  display: inline-block;
  flex: 1;
  padding: 1.5em 1em;
}

.search__button { // Block with another Element
  background-color: #000;
  color: #FFF;
  display: inline-block;
  font-size: 1.25em;
}

How can it help modularity?

Now that our class names are dependent on the blocks, we can create stylesheets based on them, and, with Sass, nest any contextual modifiers underneath. Using our example above, all of our styles for the search feature could be held in a singular search.scss file. I used to have the bad habit of structuring my stylesheets based around views and layout. If I wanted the landing page’s search to be more prominent than the one in the header, I may have manipulated the .search { ... } selector within my landing.scss and header.scss files. Clearly that is not ideal or maintainable if more instances of the search form exist. Instead, we can use Sass’ parent selectors write something like:

// Filename: search.scss

.search {
  align-content: center;
  display: flex;

  &--is-disabled {
    display: none;
  }
}

.search__input {
  border: 1px #000 solid;
  display: inline-block;
  flex: 1;
  padding: 1.5em 1em;

  // Landing page specific styles
  .landing & {
    padding: 2.5em 2em;
  }
}

.search__button {
  background-color: #000;
  color: #FFF;
  display: inline-block;
  font-size: 1.25em;

  // Landing page specific styles
  .landing & {
    font-size: 1.5em;
  }
}

This way, if any blocks or their elements needed to be changed for certain pages, you know to go straight into the dedicated stylesheet for that feature, rather than needing to backtrack and remember which layout sheet held what styles.

How does it match with MVC?

From a front-end development point of view, I found the rationale behind MVC and BEM to be similar. This means that when working on, say, a Rails project, I could keep the same mindset for writing both markup and styles. In the MVC pattern, models dictate how the app and data is structured, and each model describes a set of data. In BEM, blocks—like navigations and forms—make up the interface for the app. Each block can describe one UI object (e.g our search form) or a set of data too (e.g. a .user with a .user__name and .user__birthday), and there can be multiple copies of it on the DOM. With views, it is possible to display a model’s data in varied ways without changing the information itself. Similarly, using modifier classes and parent selectors, you can tweak the visual treatments for many instances of one block.

What if I don’t like the syntax?

In all our discussions about BEM, the fact that it uses underscores and dashes in its naming system always get brought up. Some team members find them too distracting to adopt BEM in their workflow. However, I firmly believe that there’s no reason for the dogma and it’s not the specific use of __ and -- that makes BEM, BEM. If you prefer to use single dashes or other ways of seperating your B’s, E’s and M’s, the methodogy is more than flexible to accommodate your preferences. While the specific syntax may not be for everyone, BEM is undoubtedly an effective way to organize your front-end. Even if you don’t like the syntax, I’d encourage you to try BEM out anyway and tweak it to your liking.

Additional notes

Read the documentation over on BEM’s official page.

Using Hound?

Are you using Hound for SCSS linting? By default, it does not support BEM syntax. However, if you’re interested in having it work, add the following to its corresponding files:

In hound.yml

scss:
  config_file: config/scss.yml

In config/scss.yml

SelectorFormat:
  enabled: true
  convention: BEM