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:
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:
On the JavaScript side it means:
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:
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
Example:
An element modifier changes the look of the “current” item
From the input data point of view:
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:
<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;
}
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:
From the CSS point of view:
.menu {
__layout {
display: inline;
}
__layout-item {
display: inline-block;
...
}
__item {
_state_current {
font-weight: bold;
}
}
}
On the JavaScript side:
$('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)
A website has a Button block with certain dynamic behavior.
When a block is hovered, it changes its appearance.
A manager could ask:
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:
If a block has dynamic behavior, we add it to this list:
Everything that constitutes a block is a technology, including images.
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.
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!
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!