The text below already became obsolete. Read the newest article instead.

What is BEM?

BEM is an approach to front-end development designed with flexibility and ease of modification in mind.

BEM helps solve the following problems:

Definitions

Block

Block is an independent entity, a "building block" of an application.
Blocks contain information about themselves and their children (block elements).
Blocks can be used on their own or as a part of other blocks.

Example
b-search - a search form block

Element

Element is a part of a block, that performs a certain function.
Block elements can only appear inside their respective blocks. Elements can be mandatory and optional.

Example
An input field and a button are elements of the b-search block

Modifier

Modifiers are properties of blocks and elements; they change appearance or behavior of the elements, they are applied to.
Each modifier has a name and a value. Multiple modifiers can be applied simultaneously.

Example
A b-search block modifier sets the background color of a block

Overloading

A project can consist of several sets of block implementations. Each set, or level, extends the higher-level set. The final implementation of a block is assembled by building the levels sequentially.

Example

Naming conventions

Block name

Block names are defined as prefix-block-name.

Examples

    b-menu
    b-popup
    i-popup

Block prefix

We commonly use two prefixes to define the designation of a block.

b- (as in block)
The b- prefix is used for blocks that have a user interface or, more generally, a visual representation.

Example
A popup window has a visual representation. It may, or may not, contain a close button, or have a balloon-like appearance. It can be displayed in different directions or have different color schemes.

i- (as in include)
The i- prefix is used for abstract blocks, which do not exist on their own, but are used to build other blocks.
i- blocks do not have a visual representation, they only implement some logic.

Example
The i-popup block does not have a visual representation, but it implements certain logic required by the b-popup block, which cannot exist without i-popup.

Element name

Element names specify unambiguously, which block the element belongs to.
Element names are defined as: b-block-name__element-name

Examples

    b-menu__item
    b-popup__content

Naming of block modifiers

Modifier names specify unambiguously, which block the modifier belongs to. Fully qualified modifier names are defined as: b-block-name_modifier-name_modifier-value.

Examples

    b-menu_layout_horiz
    b-menu_layout_vert
    b-popup_direction_up

Naming of element modifiers

Modifier names specify unambiguously, which block and which element the modifier belongs to. Fully qualified modifier names are defined as: b-block-name__element-name_modifier-name_modifier-value.

Examples

    b-menu__item_state_current
    b-popupa__content_visibile_yes
    b-popupa__content_visibile_no

Modifying the blocks

Blocks can be modified using:

Modifiers

A modifier class is added to a block or an element, and it contains the necessary appearance or behavior changes.

Examples

A b-popup block does not have background set by default.

By adding a theme modifier to the b-popup block, background color can be specified for this block.
theme=yellow specifies a yellow background:

theme=black specifies a black background:

A block can have several modifiers applied at once.

Examples

theme modifier specifies background color, direction modifier specifies dropdown behavior (whether popups should open to the left, right, etc).

theme=yellow and direction=left — popup window with yellow background, opens to the left:

theme=yellow and direction=right — popup window with yellow background, opens to the right:

Modifiers can alter the blocks' structure (by adding/removing elements) and implementation.

Example
A has-close=yes modifier adds a closing button and adjusts block's padding accordingly.

Modification by context

A block can appear or behave differently, when put inside another block.

Example
Text color of the embedded block changes from green to red, when put inside a block with blue background.

Examples

b-lang-switcher - language switcher block

b-lang-switcher block located in the footer (b-foot) - font size becomes smaller.

Modification by overloading

Appearance or behavior changes can be introduced on a higher level.

Example
The common part of the block's implementation belongs to the framework (and is stored in the framework's repository) while some local modifications belong to a specific project (and are stored in the project's repository in separate files).

See bem-bl-test for an example of modifying the common b-link implementation to suit the needs of the bem-bl-test project.

File system representation

Blocks are implemented using multiple technologies:

Depending on the puprose of a block, different sets of technologies can be used.

File system layout follows the naming conventions we described earlier. Multiple variants are possible as described below.

Each block is stored in a separate directory, elements and modifiers are stored in separate directories as well.

    blocks/
        b-menu/
            _layout/
                b-menu_layout_horiz.css
                b-menu_layout_horiz.bemhtml
                b-menu_layout_vertical.css
                b-menu_layout_vertical.bemhtml
            __elem/
                b-menu__elem.css
                b-menu__elem.bemhtml
            b-menu.css
            b-menu.js
            b-menu.bemhtml

Alternatively, elements and modifiers can be stored under block's directory in separate files.

    blocks/
        b-menu/
            b-menu_layout_horiz.css
            b-menu_layout_horiz.bemhtml
            b-menu_layout_vertical.css
            b-menu_layout_vertical.bemhtml
            b-menu__elem.css
            b-menu__elem.bemhtml
            b-menu.css
            b-menu.js
            b-menu.bemhtml

A layout where the code for elements and modifiers is stored in blocks' files is allowed as well:

    blocks/
        b-menu/
            b-menu.css
            b-menu.js
            b-menu.bemhtml

You can also do this (no directories; elements and modifiers in separate files):

    blocks/
        b-menu_layout_horiz.css
        b-menu_layout_horiz.bemhtml
        b-menu_layout_vertical.css
        b-menu_layout_vertical.bemhtml
        b-menu__elem.css
        b-menu__elem.bemhtml
        b-menu.css
        b-menu.js
        b-menu.bemhtml

Or this (no directories; the code for elements and modifiers is stored in blocks' files):

    blocks/
        b-menu.css
        b-menu.js
        b-menu.bemhtml

BEM technologies

BEM blocks are usually implemented using multiple technologies.

HTML

Two different approaches to HTML markup are possible:

http:clubs.ya.ru/bem/replies.xml?item_no=712

Using HTML tags and CSS classes

Each BEM entity is defined by an HTML tag and corresponding CSS classes.

    <div class="block-name">
        <i class="block-name__elem"></i>
        ...
    </div>
    <div class="block-name block-name_modifier">...</div>

Custom HTML tags

Making one step further, we can partially replace standard HTML tags with custom ones.

    <copyright>
        <copyright-elem>...</copyright-elem>
        ...
    </copyright>
    <copyright class="block-name_modifier">...</copyright>

CSS

Each BEM entity must have a CSS class to allow modification.

As blocks are inherently non-unique and can be reused, only CSS classes are allowed, not IDs.

Important: ID-based CSS selectors are *NOT ALLOWED*:

    #header {}

The naming of CSS classes of BEM entities must follow the [naming conventions](#naming)

Examples of naming

 .b-popup {}                 // CSS class of a block
 .b-popup__content {}        // CSS class of an element
 .b-popupa_theme_yellow {}   // CSS class of a modifier

Usage of type selectors is allowed but actively discouraged.

Examples of non-recommended selectors:

    p
    {
    	color: #ccc;
    }

    table.news td
    {
    	border-bottom: 1px solid #ccc;
    }

    .list li
    {
    	float: left;
    }

Avoiding of type selectors significantly improves page rendering performance, known as Reflow Time — time spent by the browser during application of a stylesheet to a DOM tree.
More information is provided in this blog post (in Russian)

JavaScript

JavaScript code can also be written in BEM terms - for example, instead of working with CSS classes directly, we can add, remove, or test for blocks, elements, modifiers. The exact DOM representation is treated as a low-level implementation detail.
Blocks without a DOM representation are allowed as well - they usually provide helper functionality.

Examples of blocks without a DOM representation:

    i-request                // Generic request generator
    i-request_type_ajax      // Ajax request generator

A client-side JS framework called i-bem is provided as part of the bem-bl library:

Templates

Blocks can be implemented using templates, which use some input data to build HTML.

The bem-bl library uses bemhtml as a templating mechanism.

bemhtml is a superset of the xjst templater. Templates written in bemhtml are compiled down to plain JavaScript and can be executed both in server- and client-side environments.

DOM representation

In the simplest form, a block is represented by a single DOM node, but generally blocks and DOM nodes are not the same thing.

Mixin

Mixins are just that - usage of several blocks and/or elements on the same DOM node.

A single DOM node can represent:

Example

The tabbed pane block includes tabs (b-tabbed-pane__tabs) and panels (b-tabbed-pane__panels) as its elements. Both elements are applied to a single DOM node. This allows toggling of the panel's visual representation from vertical to horizontal.

Vertical tabbed pane

    <div class="b-tabbed-pane b-tabbed-pane__tabs">
        ...
    </div>
    <div class="b-tabbed-pane b-tabbed-pane__panels">
        ...
    </div>

Horizontal tabbed pane

    <table class="b-layout-table">
    <tr>
        <td class="b-layout-table__column b-layout-table__column_side_left">
            <div class="b-tabbed-pane b-tabbed-pane__tabs">
                ...
            </div>
        </td>
        <td class="b-layout-table__column b-layout-table__column_side_right">
            <div class="b-tabbed-pane b-tabbed-pane__panels">
                ...
            </div>
        </td>
    </tr>
    </table>

File system structure of a BEM-based project

A typical BEM project contains one or more block levels and the page code itself.

The following layout examples are recommendations, not requirements.

Pages

A page is the sum total of files that define visual appearance and behavior of a given page.

Example

    pages/
        index/
            index.css
            index.js
            index.bemhtml
            index.bemdecl.js
            index.bemjson.js

Pages are defined using a block declaration file (.bemdecl) and a block implementation file (.bemjson). These two are the "page source" and are used to generate the final CSS and JS code.

Page source

index.bemdecl.js

The b-page page uses b-menu and b-link blocks.

Example

exports.blocks = [ { "name": "b-page" }, { "name": "b-menu", "mods": [ { "name": "layout", "vals": [ "horiz" ] }, { "name": "theme", "vals": [ "red" ] } ], "elems": [ { "name": "item", "mods": [ { "name": "state", "vals": [ "current" ] } ] } ] }, { "name": "b-link" } ]
index.bemjson.js

The b-page page uses b-menu and b-link blocks.

Example

    ({
        block: 'b-page',
        content: {
            block: 'b-menu',
            mods: { layout: 'horiz', theme: 'red' },
            content: [
                {
                    elem: 'item',
                    elemMods: { state: 'current' },
                    content: 'Home page'
                },
                {
                    elem: 'item',
                    content: {
                        block: 'b-link',
                        url: '/',
                        content: 'My bookmarks'
                    }
                },
                {
                    elem: 'item',
                    content: {
                        block: 'b-link',
                        url: '/',
                        content: 'Search'
                    }
                },
                {
                    elem: 'item',
                    content: {
                        block: 'b-link',
                        url: '/',
                        content: 'About'
                    }
                }
            ]
        }
    })

Generated files

index.css

The b-page page uses b-menu and b-link blocks

Example

    @import url(../../bem-bl/blocks-desktop/b-menu/b-menu.css);
    @import url(../../bem-bl/blocks-desktop/b-menu/item/b-menu__item.css);
    @import url(../../bem-bl/blocks-desktop/b-menu/item/_state/b-menu__item_state_current.css);
    @import url(../../bem-bl/blocks-desktop/blocks/b-menu/_layout/b-menu_layout_horiz.css);
    @import url(../../bem-bl/blocks-desktop/b-link/b-link.css);
    @import url(blocks/b-menu/_theme/b-menu_theme_red.css);
index.js

The b-page page uses b-menu and b-link blocks

    include("../../bem-bl/blocks-desktop/i-jquery/__inherit/i-jquery__inherit.js");
    include("../../bem-bl/blocks-desktop/i-jquery/__identify/i-jquery__identify.js");
    include("../../bem-bl/blocks-desktop/i-jquery/__is-empty-object/i-jquery__is-empty-object.js");
    include("../../bem-bl/blocks-desktopery/__debounce/i-jquery__debounce.js");
    include("../../bem-bl/blocks-desktop/i-jquery/__observable/i-jquery__observable.js");
    include("../../bem-bl/blocks-desktop/i-bem/i-bem.js");
    include("../../bem-bl/blocks-desktop/i-bem/__internal/i-bem__internal.js");
    include("../../bem-bl/blocks-desktop/i-jquery/__stringify/i-jquery__stringify.js");
    include("../../bem-bl/blocks-desktop/i-bem/html/i-bem__html.js");
    include("../../bem-bl/blocks-desktop/i-jquery/__leftclick/i-jquery__leftclick.js");
    include("../../bem-bl/blocks-desktop/i-bem/__dom/i-bem__dom.js");
    include("../../bem-bl/blocks-desktop/i-bem/__dom/_init/i-bem__dom_init_auto.js");

Overloading

A project can consist of several sets of block implementations. Each set, or level, extends the higher-level set. A minimum of 1 set is required.

A block can be defined on several levels. A combination of levels used can be defined on a per-page level. The final implementation of the block is assembled by building the levels sequentially.

Defining levels

Project blocks only
    project/
        blocks/
            b-head/
                b-head.css
                b-head.bemhtml
            b-foot/
                b-foot.css
                b-foot.bemhtml
            b-sidebar/
                b-sidebar.css
                b-sidebar.bemhtml
Project blocks and page blocks
    project/
        blocks/
            b-head/
                b-head.css
                b-head.bemhtml
            b-foot/
                b-foot.css
                b-foot.bemhtml
            b-page/
                b-page.bemhtml
            b-sidebar/
                b-sidebar.css
                b-sidebar.bemhtml
        pages/
            index/
                blocks/
                    b-head/
                        b-head.css
                        # b-head is redefined for the index page
            about/
                blocks/
                    b-about-text/
                    # a new block added specifically for the index page
                        b-about-text.css
                        b-about-text.bemhtml
Framework blocks and project blocks
    project/
        framework/
            b-menu/
                b-menu.css
                b-menu.bemhtml
            b-page/
                b-page.css
                b-page.bemhtml
        blocks/
            b-head/
                b-head.css
                b-head.bemhtml
            b-foot/
                b-foot.css
                b-foot.bemhtml
            b-page/
            # redefines the b-page block defined on a higher (framework) level
                b-page.bemhtml
            b-sidebar/
                b-sidebar.css
                b-sidebar.bemhtml
Framework, project, and page blocks
    project/
        framework/
            b-menu/
                b-menu.css
                b-menu.bemhtml
            b-page/
                b-page.css
                b-page.bemhtml
        blocks/
            b-head/
                b-head.css
                b-head.bemhtml
            b-foot/
                b-foot.css
                b-foot.bemhtml
            b-page/
            # Redefines the b-page block defined on a higher (framework) level
                b-page.bemhtml
            b-sidebar/
                b-sidebar.css
                b-sidebar.bemhtml
        pages/
            index/
                blocks/
                    b-head/
                        b-head.css
                        # b-head is redefined for the index page
            about/
                blocks/
                    b-about-text/
                    # a new block added specifically for the index page
                        b-about-text.css
                        b-about-text.bemhtml
Project, page, and theme blocks
    project/
        blocks/
            b-head/
                b-head.css
                b-head.bemhtml
            b-foot/
                b-foot.css
                b-foot.bemhtml
            b-page/
            # Redefines the b-page block defined on a higher (framework) level
                b-page.bemhtml
            b-sidebar/
                b-sidebar.css
                b-sidebar.bemhtml
        pages/
            index/
                blocks/
                    b-head/
                        b-head.css
                        # b-head is redefined for the index page
            about/
                blocks/
                    b-about-text/
                    # a new block added specifically for the index page
                        b-about-text.css
                        b-about-text.bemhtml
        themes/
            black/
            # Files, which define the 'black' color scheme (stored in the same directory)
                b-head.css
                b-foot.css
                b-sidebar.css
            yellow/
                b-head.css
                b-foot.css
                b-sidebar.css

Implementing a block

Blocks are implemented using multiple technologies:

Depending on the puprose of a block, different sets of technologies can be used.
Structure matters most - implementation details are secondary.

Example of a b-domik block (login form)

Домик на странице
Login house on page
Домик в попапе
Login house in popup
    b-domik/
    # common files
        b-domik.css
        b-domik.ie.css
        b-domik.js
        b-domik.xsl
        # modifiers
        _type/
            b-domik_type_onpage.css    # login form on the page
            b-domik_type_onpage.ie.css
            b-domik_type_onpage.js
            b-domik_type_onpage.xsl
            b-domik_type_popup.css    # login form in a popup
            b-domik_type_popup.ie.css
            b-domik_type_popup.js
            b-domik_type_popup.xsl
        __lock/
        # "lock" element (denotes secure login)
            b-domik__lock.css
            b-domik__lock.png
            b-domik__lock.xsl
            _visibility/
            # a modifier of the "lock" element which makes the element visible
                b-domik__lock_visibility_visible.css
        __shadow/
        # "shadow" element
            b-domik__shadow.css
            b-domik__shadow.ie.css
            b-domik__shadow.png

Toolkit

bem-tools command-line tools are being developed to enhance development experience. BEM tools include a command-line utility, that can be used to quickly create BEM source files using different technologies (HTML/CSS/JS), and a BEM compiler.

Main repository is at bem-tools

Useful links (all in Russian)

Related links

Source code repositories