A New Front-End Methodology: BEM (Blocks Reiteration)

BEM stands for “Block”, “Element”, “Modifier”. It is a front-end methodology: a new way of thinking when developing Web interfaces. This article will elaborate on the theory as well as the practice of building websites at Yandex—one of the leading internet companies in Russia.

Due to the length of this article, it was split into three parts:

Blocks Reiteration

The second Menu Block can occur in the Foot Block of a website. Also, a Text Block can divide into two, separated by an advertisement.

Even if a block was developed as a singular unit, the same one can appear on a page at any moment.

In CSS related terms, this means:

  • ID-based CSS selectors must not be used.
    Only class selectors satisfy our non-uniqueness requirement.

On the JavaScript side it means:

  • Blocks with similar behavior are detected unequivocally—they have the same CSS classes.
    Using CSS class selectors allows for picking all blocks with a given name to apply the required dynamic behavior.

Modifiers For Elements And Blocks

We often need to create a block very similar to an existing one, but with a slightly altered appearance or behavior.
Let’s say, we have a task:

  • Add another Menu in the Footer with a different layout.

To avoid developing another block that is only minimally different from an existing one, we can use a Modifier.

A Modifier is a property of a block or an element that alters its look or behavior. A modifier has both a name and a value. Several modifiers can be used at once.

Example:
A block modifier specifies background color

search background

Example:
An element modifier changes the look of the “current” item

current item in menu

From the input data point of view:

  • In a BEM tree, modifiers are properties of an entity that describes a block or an element.

For example, they can be attribute nodes in XML:

<b:menu m:size="big" m:type="buttons">

... </b:menu>

The same expressed in JSON:

{
  block: 'menu',
  mods: [
   { size: 'big' },
   { type: 'buttons' }
  ]
}

From the CSS point of view:

  • A modifier is an additional CSS class for a block or an element.
<ul class="menu menu_size_big menu_type_buttons">
  ...
</ul>
.menu_size_big {
  // CSS code to specify height
}
.menu_type_buttons .menu__item {
  // CSS code to change item's look
}

Element modifiers are implemented in the same fashion. Again, when writing CSS by hand, it’s very important to use separators consistently for programmatic access.

E.g., current menu item can be marked with a modifier:

<b:menu>
  <e:item>Index<e:item>
  <e:item m:state="current">Products</e:item>
  <e:item>Contact<e:item>
</b:menu>
{
  block: 'menu',
  content: [
    { elem: 'item', content: 'Index' },
    {
      elem: 'item',
      mods: { 'state' : 'current' },
      content: 'Products'
    },
    { elem: 'item', content: 'Contact' }
  ]
}
<div class="menu">
  <ul class="menu__layout">
    <li class="menu__layout-unit">
      <div class="menu__item">Index</div>
    </li>
    <li class="menu__layout-unit">
      <div class="menu__item menu__item_state_current">Products</div>
    </li>
    <li class="menu__layout-unit">
      <div class="menu__item">Contact</div>
    </li>
  </ul>
</div>
.menu__item_state_current {
  font-weight: bold;
}

Subject-Matter Abstraction

When many people work on a project, they should agree on a data domain and use it when naming their blocks and elements.

For example, a Tag Cloud block is always named Tags. Each of its elements is a Tag. This convention spreads across all languages: CSS, JavaScript, XSL, etc.

From the development process’ point of view:

  • All participants operate on the same terms.

From the CSS point of view:

  • CSS for blocks and elements can be written in a pseudo language that compiles down to CSS according to the naming convention.
  .menu {
    __layout {
      display: inline;
    }
    __layout-item {
      display: inline-block;
      ...
    }
    __item {
      _state_current {
        font-weight: bold;
      }
    }
  }

On the JavaScript side:

  • Instead of using class selectors directly to find DOM elements, a special helper library may be used.
$('menu__item').click( ... );
$('menu__item').addClass('menu__item_state_current');
$('menu').toggle('menu_size_big').toggle('menu_size_small');

The naming convention for CSS classes of blocks and elements can change over the course of time. Using special JavaScript functions to access blocks and elements (and to work with their modifiers) makes it possible to change only these functions if the naming convention changes.

Block('menu').elem('item').click( ... );
Block('menu').elem('item').setMod('state', 'current');
Block('menu').toggleMod('size', 'big', 'small');

The code above is abstract. In real life we use the JavaScript core of i-bem block from the bem-bl block library: http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.ru.html (described in Russian)

Blocks Consistency

A website has a Button block with certain dynamic behavior.

When a block is hovered, it changes its appearance.

A manager could ask:

  • To use the same button on another page.

Having a CSS implementation of a block is not enough. Reusing a block also means reusing its behavior, described in JavaScript.

So a block must “know” everything about itself. To implement a block, we describe its appearance and behavior in all technologies being used—we call that Multilingualism.

Multilingual presentation is a description of a block in all the programming languages that are necessary to implement the view and the functionality of that block.

To have a block present on a page as a UI element, we need to implement it in the following techs:

  • Templates (XSL, TT2, JavaScript, etc), which turn block declarations into HTML code.
  • CSS that describes appearance of the block.

If a block has dynamic behavior, we add it to this list:

  • A JavaScript implementation for the block.

Everything that constitutes a block is a technology, including images.

Smashing Special: A Three-Part Article

Due to the length of the article, it was split into three parts:

(jvb)

I am a front-end developer working for Yandex since 2008. Now being a team-leader of development an UI framework (CSS/HTML/JavaScript + templates) for building Yandex-style sites, I'm also pushing some internal front-end technical solutions into Open Source.

  1. 00

    No comments have been posted yet. Please feel free to comment first!
    Note: Make sure your comment is related to the topic of the article above. Let's start a personal and meaningful conversation!

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top