Varvara Stepanova

About The Author

Varvara Stepanova 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.

A New Front-End Methodology: BEM

This article is the sixth in our new series that introduces the latest, useful and freely available tools and techniques, developed and released by active members of the Web design community. The first article covered PrefixFree; the second introduced Foundation, a responsive framework; the third presented Sisyphus.js, a library for Gmail-like client-side drafts, the fourth covered a free...

This article is the sixth in our new series that introduces the latest, useful and freely available tools and techniques, developed and released by active members of the Web design community. The first article covered PrefixFree; the second introduced Foundation, a responsive framework; the third presented Sisyphus.js, a library for Gmail-like client-side drafts, the fourth shared with us a free plugin called GuideGuide and the fifth presented Erskine Design's responsive grid generator Gridpak. Today, we are happy to feature a toolkit devised by Yandex: BEM.

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:

BEM Principles

To begin, let's first put BEM in some historical perspective.

We first began sketching out the internal front-end framework at Yandex around the year 2007, starting with a robust CSS naming convention, and a file system layout that was associated with it. Since the naming convention was well-structured, it seemed suitable to develop certain JavaScript helpers (to work with the DOM and CSS classes in particular, on a higher level of abstraction). We then used those approaches to build an internal library of UI components that could be shared among our various websites and rich applications, built using different technology stacks (XML/XSLT, Python/Django, Perl/TT2).

As our ambitions, complexity and performance requirements grew, we aimed at replacing XSLT and Perl templates with a JS-based declarative templating DSL, built on top of Node.js. Along with those efforts, we looked into simplifying development workflow and developed a bunch of command-line tools that already helped us manage front-end code on the file system, preprocess CSS and JavaScript code, and so on, and so forth.

Some parts of the BEM stack started as open source projects, while others (like the UI component library) are being gradually open sourced. Our goal is to publish most of them during 2012.

BEM is a toolkit that will help address and resolve front-end issues quickly and effectively. It is available in a range of reusable code libraries—all of them are hosted on Github and are completely open source.

BEM Principles

One of the most common examples of a methodology in programming is Object-Oriented Programming. It's a programming paradigm embodied by many languages. In some ways, BEM is similar to OOP—a way of describing reality in code, with a range of patterns, and a way of thinking about program entities regardless of the programming languages being used.

We've used BEM principles to create a set of front-end development techniques and tools that allow us to build websites quickly and maintain them over a long period of time. The principles are the following:

Unified Data Domain

Imagine an ordinary website, like the one pictured below:

ordinary website example

While developing such a website, it's useful to mark out "blocks" from which the website consists of. For example, in this picture there are Head, Main Layout and Foot blocks. The Head in turn consists of Logo, Search, Auth Block and Menu. Main Layout contains a Page Title and a Text Block:

site marked

Giving each part of the page a name is very useful when it comes to team communication.

A project manager could ask:

  • To make the Head bigger, or
  • To create a page without a Search form in the Head.

An HTML guy could ask a fellow JavaScript developer:

  • To make Auth Block animated, etc.

Let's now take a closer look at what constitutes BEM:

Block

A block is an independent entity, a "building block" of an application. A block can be either simple or compound (containing other blocks).

Example Search form block:

search form block

Element

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 that they belong to.

Example

An input field and a button are elements of the Search Block:

elements of search block

Means Of Describing Pages And Templates

Blocks and elements constitute page content. Besides simply being present on a page, their arrangement is also important.

Blocks (or elements) may follow each other in a certain order. For example, a list of goods on a commerce website:

list of goods on a commerce website

...or menu items:

menu items

Blocks may also be contained inside other blocks. For example, a Head Block includes other blocks:

blocks inside other blocks

Besides, our building blocks need a way to describe page layout in plain text. To do so, every block and element should have a keyword that identifies it.

A keyword designating a specific block is called Block Name. For example, Menu can be a keyword for the Menu Block and Head can be a keyword for the Head block.

A keyword designating an element is called Element Name. For example, each item in a menu is an element Item of the Menu block.

Block names must be unique within a project to unequivocally designate which block is being described. Only instances of the same block can have the same names. In this case, we can say that one block is present on the page twice (or 3, 4, times... etc.).

Element names must be unique within the scope of a block. An element can be repeated several times. For example, menu items:

repeated elements

Keywords should be put in a certain order. Any data format that supports nesting (XML, JSON) will do:

<b:page>
  <b:head>
    <b:menu>
      ...
    </b:menu>
    <e:column>
      <b:logo/>
    </e:column>
    <e:column>
      <b:search>
        <e:input/>
        <e:button>Search</e:button>
      </b:search>
    </e:column>
    <e:column>
      <b:auth>
        ...
      </b:auth>
    <e:column>
  </b:head>
</b:page>

In this example, b and e namespaces separate block nodes from element nodes.

The same in JSON:

{
  block: 'page',
  content: {
    block: 'head',
    content: [
      { block: 'menu', content: ... },
      {
        elem: 'column',
        content: { block: 'logo' }
      },
      {
        elem: 'column',
        content: [
          {
            block: 'search',
            content: [
              { elem: 'input' },
              {
                elem: 'button',
                content: 'Search'
              }
            ]
          }
        ]
      },
      {
        elem: 'column',
        content: {
          block: 'auth',
          content: ...
        }
      }
    ]
  }
}

Examples above show an object model with blocks and elements nested inside each other. This structure can also contain any number of custom data fields. We call this structure BEM Tree (by analogy with DOM tree).

Final browser markup is generated by applying template transformations (using XSL or JavaScript) to a BEM tree.

If a developer needs to move a block to a different place on a page, he does so by changing the BEM tree. Templates generate the final view themselves.

In our recent products we went with JSON as a page description format. It is then turned into HTML by a JS-based template engine. The tools we use are listed at the end of this article.

Block Independence

As projects grow, blocks tend to be added, removed, or moved around on the page. For example, you may want to swap the Logo with the Auth Block, or place the Menu under the Search Block.

swapping blocks

To make this process easier, blocks must be Independent.

An Independent block is implemented in a way that allows arbitrary placement anywhere on the page—including nesting inside another block.

Independent CSS

From the CSS point of view it means that:

  • A block (or an element) must have a unique "name" (a CSS class) that could be used in a CSS rule.
  • HTML elements must not be used in CSS selectors (.menu td) as such selectors are inherently not context-free.
  • Cascading selectors for several blocks should be avoided.
Naming for Independent CSS Classes

One of the possible naming schemes for CSS classes that satisfies said requirements is the following:

  • CSS class for a block coincides with its Block Name.
<ul class="menu">
  ...
</ul>
  • CSS class for an element is a Block Name and an Element Name separated by some character(s)
<ul class="menu">
  <li class="menu__item">
    ...
  </li>
  <li class="menu__item">
    ...
  </li>
</ul>

It's necessary to include block name in a CSS class for an element to minimize cascading. It's also important to use separators consistently to allow the tools and helpers to have unambiguous programmatic access to the elements.

Different naming schemes can be used. Take a look here for the naming convention we used.

Independent Templates

From the template engine's perspective, block independence means that:

  • Blocks and elements must be described in the input data. Blocks (or elements) must have unique "names" to make things like "Menu should be placed here" expressible in our templates.
  • Blocks may appear anywhere in a BEM tree.
Independent templates for blocks

When coming across a block in a template, the template engine should be able to unambiguously transform it into HTML. Thus, every block should have a template for that.

For example, a template can look like this in XSL:

<xsl:template match="b:menu">
  <ul class="menu">
    <xsl:apply-templates/>
  </ul>
</xsl:template>

<xsl:template match="b:menu/e:item">
  <li class="menu__item">
    <xsl:apply-templates/>
  </li>
<xsl:template>

We are gradually discarding XSLT in our products in favor of our own JavaScript-based template engine XJST. This template engine absorbs everything we like about XSLT (we are fans of declarative programming), and implements it with JavaScript's productivity on either the client or the server side.

We, at Yandex, write our templates using a domain-specific language called BEMHTML, which is based on XJST. The main ideas of BEMHTML are published in the BEM club on Ya.Ru (in Russian).

Smashing Special: A Three-Part Article

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

(jvb)


More Articles on

CSS Sprites Revisited

by Niels Matthijs

I’m pretty confident that I won’t surprise anyone here by saying that CSS sprites have been around for quite a while now, rearing their somewhat controversial heads in the Web development sphere as early as 2003. Still, the CSS sprite hasn’t truly found its way into the everyday toolkit of the common Web developer. While the theory behind CSS sprites is easy enough and its advantages...

Read more

Device-Agnostic Approach To Responsive Web Design

by Thierry Koblentz

This is a different take on Responsive Web design. This article discusses how we can better embrace what the Web is about by ignoring the big elephant in the room; that is, how we can rely on media queries and breakpoints without any concern for devices. Let’s start our journey by looking at the online tools such as Responsive Design Testing, Responsive.is, Responsinator and BriCSS....

Read more

Gridpak: The Responsive Grid Generator

by Erskine Design

This article is the fifth in our new series that introduces the latest, useful and freely available tools and techniques, developed and released by active members of the Web design community. The first article covered PrefixFree; the second introduced Foundation, a responsive framework; the third presented Sisyphus.js, a library for Gmail-like client-side drafts and the fourth shared with us a...

Read more