CSS Architecture Block-Element-Modifier (BEM)

Tiffany Brown
Share

The following is an extract from our book, CSS Master, written by Tiffany Brown. Copies are sold in stores worldwide, or you can buy it in ebook form here.

BEM, or Block-Element-Modifier, is a methodology, a naming system, and a suite of related tools. Created at Yandex, BEM was designed for rapid development by sizable development teams. In this section, we’ll focus on the concept and the naming system.

BEM methodology encourages designers and developers to think of a website as a collection of reusable component blocks that can be mixed and matched to create interfaces. A block is simply a section of a document, such as a header, footer, or sidebar, illustrated in Figure 2.3. Perhaps confusingly, “block” here refers to the segments of HTML that make up a page or application.

Figure 2.3. A home page might have header, main, and footer blocks

Blocks can contain other blocks. For example, a header block might also contain logo, navigation, and search form blocks as seen in Figure 2.4. A footer block might contain a site map block.

Figure 2.4. A header block that contains logo, navigation, and search blocks

More granular than a block is an element. As the BEM documentation explains:

An element is a part of a block that performs a certain function. Elements are context-dependent: they only make sense in the context of the block they belong to.

A search form block, for example, contains a text input element and a submit button element, as evident in Figure 2.5. To clarify, we’re using “element” in the design element sense rather than the HTML element sense.

Figure 2.5. A search block with text input and submit button elements

A main content block, on the other hand, might have an article list block. This article list block might contain a series of article promo blocks. And each article promo block might contain image, excerpt, and Read More elements, as presented in Figure 2.6.

Figure 2.6. A promotional block for a website article

Together, blocks and elements form the basis of the BEM naming convention. According to the rules of BEM:

  • Block names must be unique within a project.
  • Element names must be unique within a block.
  • Variations of a block―say, a search box with a dark background―should add a modifier to the class name.
  • Block names and element names are usually separated by a double underscore (.block__element). Block and element names are typically separated from modifier names by a double hyphen (for example, .block--modifier or .block__element--modifier).

    Here’s what BEM looks like using a search form example:

    <form class="search"> 
      <div class="search__wrapper"> 
        <label for="s" class="search__label">Search for: </label> 
        <input type="text" id="s" class="search__input"/>
        <button type="submit" class="search__submit">Search</button> 
      </div> 
    </form>

    A variation of this form with a dark background might use the following markup:

    <form class="search search--inverse"> 
      <div class="search__wrapper search__wrapper--inverse"> 
      <label for="s" class="search__label search_label--inverse">
    ↵Search for: </label> 
      <input type="text" id="s" class="search__input search__input ↵--inverse"> 
      <button type="submit" class="search__submit search__submit-
    ↵inverse">Search</button> 
      </div> 
    </form>

    Our CSS might look like this:

    .search {
        color: #333;
    }
    .search--inverse {
        color: #fff;
        background: #333;
    }
    .search__submit {
        background: #333;
        border: 0;
        color: #fff;
        height: 2rem;
        display: inline-block;
    }
    .search__submit--inverse {
        color: #333;
        background: #ccc;
    }

    In both our markup and CSS, search--inverse and search__label--inverse are additional class names. They’re not replacements for search and search__label. Class names are the only type of selector used in a BEM system. Child and descendant selectors may be used, but descendants should also be class names. Element and ID selectors are verboten. This ensures that selector specificity remains low, selectors are without side effects, and CSS is independent of markup patterns. Enforcing block and element name uniqueness also prevents naming collisions, which can become a problem among teams.

    There are several advantages to this approach:

  • it’s easy for new team members to read the markup and CSS, and understand its behavior
  • adding more developers increases team productivity
  • consistent naming reduces the possibility of class name collisions and side effects
  • CSS is independent of markup
  • CSS is highly reusable

There’s a lot more to BEM than what can comfortably fit in a section of a chapter. The BEM site describes this methodology in much greater detail, and also features tools and tutorials to get you started. To learn more about the naming convention aspect of BEM, another fantastic resource is Get BEM.