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.

3

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 background4

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

current item in menu5

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.html6 (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)

Footnotes

  1. 1 http://coding.smashingmagazine.com/2012/04/16/a-new-front-end-methodology-bem/
  2. 2 http://coding.smashingmagazine.com/front-end-methodology-bem-file-system-representation/
  3. 3 http://coding.smashingmagazine.com/wp-content/uploads/2012/03/site-footer-menu.png
  4. 4 http://coding.smashingmagazine.com/wp-content/uploads/2012/03/search-background.png
  5. 5 http://coding.smashingmagazine.com/wp-content/uploads/2012/03/menu-current-item.png
  6. 6 http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.ru.html?from=smashingmagazine
  7. 7 http://coding.smashingmagazine.com/2012/04/16/a-new-front-end-methodology-bem/
  8. 8 http://coding.smashingmagazine.com/front-end-methodology-bem-file-system-representation/

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.

Advertising
  1. 1

    I love OOCSS, but I’m not very fond of BEM. While OOCSS leads to shorter, more efficient, more elegant and more reusable CSS code, BEM does de exact opposite.

    First of all, I see no valid reason to distinguish between blocks and elements. Why should there be two types of elementary building block when you could just have one type?

    Also, it makes no sense to use selectors like “.menu__item” instead of “.menu .item” or “.menu > .item”. It makes your HTML code more convoluted, it adds bloat to your CSS and it restricts reuse of shared CSS rules.

    The same is true for modifiers. Why use “.menu_size_big” and “.menu_type_buttons” when you could use “.menu.big” and “.menu.buttons” or even “.menu .big” and “.menu .buttons”? Why must the modifiers be so overly restrictive?

    Consider the following syntax for a basic navigation element :

    <ul class=”nav “>[ ... ]</ul>

    Different types of navigation could be defined by wrapping this element in a div with a functional modifier :

    <div class=”menu”><ul class=”nav”>[ ... ]</ul></div>
    <div class=”tabs”><ul class=”nav”>[ ... ]</ul></div>
    <div class=”tags”><ul class=”nav”>[ ... ]</ul></div>

    An additional modifier can be used to adjust the orientation (where relevant) or further refine the behavior :

    <div class=”menu”><ul class=”left nav”>[ ... ]</ul></div>
    <div class=”tabs”><ul class=”bottom nav”>[ ... ]</ul></div>
    <div class=”menu”><ul class=”tree nav”>[ ... ]</ul></div>
    <div class=”tags”><ul class=”blocks nav”>[ ... ] </ul></div>

    Functionality shared by all navigation elements can then be defined using the “.nav” selector.

    Functionality specific to a navigation type can be defined using selectors like “.menu .nav”, “.tabs .nav” or “.tags .nav”.

    Selectors like “.left” and “.tree” (or “ul.left” and “ul.tree”) can be used to define behavior for different nagivation types that share the same orientation or specific behavior.

    Such an implementation keeps both the CSS code and HTML code very DRY, is supported by older browsers (including IE6) and provides endless possibilities with regards to combining different elements / blocks.

    See http://cascade-framework.com/ for a CSS framework based on that strategy.

    -2

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 else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top