No answer found? — Place your question on our forum!
Find out more about the BEM methodology.
It is possible to use BEM at the CSS level only. You just need to follow the guidelines proposed by the methodology.
Browser support
Encapsulation
Template execution
In BEM, template generation is possible at the development stage. This lets us pass the ready HTML. Templates can be executed both in the browser and on the server side.
Web Components are based on an imperative principle, using string interpolation.
Build vs HTML import
Abstraction over a DOM tree vs Custom Elements
In BEM terms, Bootstrap is a set of ready-made blocks. BEM, on the other hand, is not a library of interface elements but a methodology that allows you to
BEM does provide its own block library, called bem-components. Other BEM libraries are also available.
This rule does not apply when implementing elements that, for reasons of simplifying the development process, have to be broken down into smaller, sub-element, parts. The BEM methodology does not recommend creating elements of elements. So, in cases like this, instead of an element, a service block should be created.
The existence of elements of elements hinders the ability to change the internal structure of the block: elements cannot be swapped around, removed or added without modifying the existing code.
In the BEM methodology, blocks are the only entities that support nested structure (block__elem
). A block name defines a namespace that ensures the dependence of elements on the block.
A block can have a nested element structure in a DOM tree.
<div class="block">
<div class="block__elem1">
<div class="block__elem2">
<div class="block__elem3"></div>
</div>
</div>
</div>
In the BEM methodology, though, the same structure is always represented by a flat list of elements.
.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}
This makes it possible to change the DOM structure of the block without modifying the code of each individual element.
<div class="block">
<div class="block__elem1">
<div class="block__elem2"></div>
</div>
<div class="block__elem3"></div>
</div>
The structure of the block changes while the rules for its elements and their names remain the same.
A block name in the names of BEM entities is used for
NB: The BEM methodology allows freedom of choice when it comes to a choosing a preferred naming strategy, however consistency of names is required. For example, the following are all valid options: context
, ctx
or c
, attributes
, attrs
or as
. Select one name and stick with it throughout the project.
A block name defines a namespace and ensures unique names for elements and modifiers. This helps reduce the impact of elements and modifiers of one block on the implementation of another.
A mix is an instance of different BEM entities being hosted on a single DOM node. When mixing a modifier, a block name indicates what block the modifier will be applied to. If a block name is not specified, the modifier will be applied to all the mixed BEM entities.
Let's say we have a mix of a menu item (menu_item
) and a button (button
:
<div class="menu__item button"></div>
Let's add a modifier called active
in short notation (with no block name):
<div class="menu__item button active"></div>
This kind of HTML markup leaves it unclear as to whether the modifier relates to the menu item (menu__item.active
) or the button (button.active
). Specifying the block name (button_active
) indicates the BEM entity to which the modifier will be applied.
Likewise, notation like <div class="block mod">
leaves it unclear as to what BEM entities are being used. For example, you can't tell from <div class="checkbox button">
whether it's a mix of a modifier and a block or a mix of two blocks.
The full name of the modifier <div class="block block_mod">
leaves no doubt as to the types of entities: <div class="checkbox checkbox_button">
.
Explicit and unique names facilitate searching the code or the file system for specific entities.
Let's compare the results of a global search during the debugging stage. Let's find a modifier called active
. If short notation is used (active
), the search results will include all possible combinations and HTML fragments containing active
. In the BEM-recommended notation the name of the modifier already contains a additional search parameter in the form of the block name (button_active
). Because the modifier name is unique, the search will return only relevant code fragments.
BEM does not accommodate the concept of global modifiers — any modifier always belongs to one specific BEM entity.
If a CSS property needs to be moved outside of a block and applied to different BEM entities in the project, a separate block should be created, implemented in the CSS technology.
BEM allows us to combine the implementation of different blocks using mixes:
<div class="block1 block2"></div>
For the purpose of convenient development and support, the file system of a BEM project is divided into nested directories and files.
The use of the recommended file system structure is optional. You can use any alternative project structure that conforms to the principles of BEM file system organization, for example:
flex scheme
blocks/
input/
input_layout_horiz.css
input_layout_vertical.css
input__elem.css
input.css
input.js
button/
blocks/
input/
input.css
input.js
button/
blocks/
input.css
input.js
button.css
button.js
flat scheme
blocks/
input_type_search.js
input_type_search.bemhtml
input__box.bemhtml
input.css
input.js
input.bemhtml
button.css
button.js
button.bemhtml
button.png
i-bem.js is a specialized framework for developing projects with JavaScript in terms of blocks, elements, and modifiers.
i-bem.js
is not meant to replace any general-purpose framework, such as jQuery.
i-bem.js
allows you to
BEM is all about independent blocks. Nested selectors increase coupling within the code and make code reuse impossible. This is in contradiction to the BEM principles.
The BEM methodology allows nested selectors, but recommends keeping their use to a minimum.
For instance, nesting is appropriate for changing elements depending on the state of a block or its assigned theme.
.nav_hovered .nav__link
{
text-decoration: underline;
}
.nav_theme_islands .nav__item
{
line-height: 1.5;
}
Combined selectors make block redefinition more difficult because of their higher CSS specificity compared to single selectors. Combined selectors for a block modifier (.block1.mod
) and for a redefined block (.block2 .block1
) have the same specificity. Block redefinition would depend only on the order of rules in the declaration.
Consider an example:
<div class="header">
<button class="button active">
</div>
The rules for the modifier active
for the button are written as the combined selector .button.active
. To redefine the button with the parent block header
, selector .header .button
is created. Both selectors have the same specificity, so the application of CSS rules is determined by their declaration order.
Using the block name in the name of a modifier gives a higher priority to CSS rules for block redefinition. The
.header .button
selector will be always of a higher priority than .button_active
.
Combining a tag and a class in one selector increases its CSS specificity. Adding a modifier won't redefine the CSS rules of the block since the specificity of the block selector is higher.
Let's look at an example:
<button class="button">
Let's use a button.button
selector for the CSS rules of this block.
Now with a modifier:
<button class="button button_active">
The .button_mod
selector will not redefine CSS properties of the block with the button.button
selector, as the latter has higher specificity. For the redefinition to work, the selector for the modifier needs to be combined with the tag as well: button.button_mod
.
As your project keeps growing, you may have blocks with selectors like input.button
, span.button
and, say, a.button
. Then all modifiers of the button
block and all its nested elements will require four different declarations for each instance.
Blocks could be represented in HTML by custom tags, with CSS rules defined for them. In that case classes would only be used for modifiers:
<button class="mod"/>
.
Custom tags can indeed be used for creating block selectors, but the following restrictions apply
<a>
tag, and all fields require <input>
.Blocks are independent components. They must not be affected by page-wide CSS rules. Otherwise their independence is compromised and their reuse becomes problematic.
A CSS Reset is carried out using global CSS rules, which are in most cases written for tag selectors, which is not recommended practice for a BEM project.
If you must reset your styles, in BEM you can do it on a per-block basis.
Here is an example. If a menu block and a list block in your project are both represented by a <ul>
tag in HTML, then each block must provide a CSS Reset for <ul>
. Duplication in the resultant code can be avoided by using a CSS optimizer.
If your project does not use a CSS optimizer that combines selectors with the same sets of rules, you can use a CSS preprocessor. Then you can have a reset of rules for every new block, mixing the proper code. E.g., in SASS it would look like this:
.menu {
@include reset-list;
}
.menu__item {
@include reset-list-item;
}
...
.list {
@include reset-list;
}
.list__item {
@include reset-list-item;
}
This method is only appropriate in the absence of an optimizer.
Using multiple modifiers on the same block (e.g., <div class="block_theme_christmas block_size_big">
) will cause duplication of the code that implements the basic functionality (logic and styles) of the block.
grey
to red
, you will need to edit the templates, and most likely, the JavaScript code.The BEM methodology recommends choosing names for modifiers based on semantics rather than visual representation.
<small>This FAQ is partially based on http://getbem.com/faq/</small>