Scaling Down The BEM Methodology For Small Projects
- 24 min read
- Coding,CSS,JavaScript,Techniques,jQuery,HTML5
- Share onTwitter, LinkedIn
Front-end development is no longer about individual frameworks. Tools are available — we merely have to choose. To make the right choices for your project,you need to start with a general approach, or methodology. But most methodologies have been created by big companies? Are they still useful for small companies, or do we need to reinvent them at a small scale?
You probably already know ofBEM, one of those methodologies developed by a big company — namely,Yandex. BEM posits that three basic entities (blocks,elements andmodifiers) are enough to define how to author HTML and CSS, structure code and components, describe interfaces and scale a project up to an industry-leading service.
I’ve spent some time with Yandex and BEM, and I know that this methodology works for large projects. Yandex uses BEM to develop CSS and JavaScript components; Yandex also optimizes templates and tracks dependencies in BEM, develops BEM utilities, supports code experiments and researches the field. On a large scale, this investment pays off and allows Yandex to develop hundreds of its services faster.
Would smaller teams benefit from BEM? I wasn’t sure. BEM is a layer of abstraction, offered with other tools and technologies. A small agile team switching to a full BEM stack would be questionable. Could the idea — the approach itself — be useful?

I had to revisit this question when my career recently took me from Yandex to Deltamethod, a mid-sized startup in Berlin. Facing ambitious development plans, we decided to try BEM on a smaller scale. We wanted the same benefits that Yandex gets from BEM:code sharing, a live style guide, scalability, faster development. We also wanted to keep our toolchain and upgrade the existing code base gradually, rather than start from scratch.
For some time, we’ve been focusing on architecture and the basics, trying aspects of BEM one by one, assessing the results, then moving forward. We keep writing down ideas, guidelines, useful tips and short tutorials. I am now convinced that BEM applies to small projects as well. I’ve written down my findings, in case you find them useful. Let’s start by reviewing the basics.
MeetSmashing Workshops onfront-end, design & UX, with practical takeaways, live sessions,video recordings and a friendly Q&A. With Brad Frost, Stéph Walter andso many others.
Jump to the workshops ↬BEM 101
While semantics is considered the foundation of web development, various front-end technologies do not share the same semantic model. The HTML of a modern app is mostly a div soup. CSS by itself does not offer any structured model at all. High-level JavaScript components use abstractions that are not consistently tied to styles or markup. At the UX level, interfaces are described in terms that have nothing in common with technical implementations. Enter BEM, a unified semantic model for markup, styles, code and UX. Let’s take a closer look.
Blocks
A block is anindependent entity with its own meaning that represents a piece of interface on a page.
Examples of blocks include:
- a heading,
- a button,
- a navigation menu.
To define a block, you’d give it a unique name and specify its semantics. Several instances of the same block definition (such as various buttons or multiple menus) might exist in the interface.
Any web interface can be represented as a hierarchical collection of blocks. The simplest representation is the HTML structure itself (tags as blocks), but that is semantically useless because HTML was designed for structured text, not web apps.
Elements
An element is apart of a block, tied to it semantically and functionally. It has no meaning outside of the block it belongs to. Not all blocks have elements.
Examples of elements include:
- a navigation menu (block) that contains menu items;
- a table (block) that contains rows, cells and headings.
Elements have names, too, and similar elements within a block (such as cells in a grid or items in a list) go by the same name. Elements aresemantic entities and not exactly the same as HTML layout; a complex HTML structure could constitute just a single element.
Modifiers
Modifiers are flags set on blocks or elements; they define properties or states. They may be boolean (for example,visible: true
orfalse
) or key-value pairs (size: large
,medium
,small
) — somewhat similar to HTML attributes, but not exactly the same. Multiple modifiers are allowed on a single item if they represent different properties.
Blocks And The DOM
How do you work with BEM while still using HTML? You do it by mapping DOM nodes to BEM entities using a naming convention.
BEM uses CSS class names to denote blocks, elements and modifiers. Blocks, elements or modifiers cannot claim any “exclusive ownership” of DOM nodes. One DOM node may host several blocks. A node may be an element within one block and (at the same time) a container for another block.
A DOM node being reused to host more than one BEM entity is called a “BEM mixin.” Please note that this is just a feature of convenience: Only combine things that can be combined — don’t turn a mix into a mess.
The BEM Tree
By consistently marking up a document with BEM entities, from the root block (i.e.<body>
or even<html>
) down to the innermost blocks, you form a semantic overlay to the DOM’s existing structure. This overlay is called a BEM tree.
The BEM tree gives you the power to manipulate the whole document in BEM terms consistently, focusing on semantics and not on a DOM-specific implementation.
Making Your First Move
You might be thinking, “I’ll give BEM a try. How do I start migrating my project to BEM? Can I do it incrementally?” Sure. Let’s start by defining some blocks. We will only cover semantics; we’ll proceed with specific technologies (like CSS and JavaScript) later on.
As you’ll recall, any standalone thing may be a block. As an example, document headings are blocks. They go without inner elements, but their levels (from top-most down to the innermost) may be defined as key-value modifiers.
If you need more levels later, define more modifiers. I would say that HTML4 got it wrong with<h1>
to<h6>
. It made different blocks (tags) of what should have been just a modifier property. HTML5 tries to remedy this with sectioning elements, but browser support is lagging.
For example, we get this:
BLOCK headingMOD level: alpha, beta, gamma
As a second example, web form input controls can be seen as blocks (including buttons). HTML didn’t get it exactly right here either. This time, different things (text inputs, radio buttons, check boxes) were combined under the same<input>
tag, while others (seemingly of the same origin) were defined with separate tags (<select>
and<textarea>
). Other things, such as<label>
and the auto-suggestiondatalist
, should be (optional) elements of these blocks because they bear little to no meaning on their own.
Let’s see if we can fix this:
BLOCK text-inputMOD multilineMOD disabled ELEMENT text-field ELEMENT label
The essential feature of a text input is its ability to accept plain text. When we need it to be multiline, nothing changes semantically — that’s whymultiline
is just a modifier. At the HTML level, this is represented by different markup for technical reasons, which is also fine because we’re only defining semantics, not the implementation. Thetextfield
tag itself is an element, andlabel
is another element; later, we might need other elements, like a status icon, error message placeholder or auto-suggestion.
BLOCK checkbox ELEMENT tick-box ELEMENT label
BLOCK radio ELEMENT radio-button ELEMENT label
These two blocks are pretty straightforward. Still,<label>
is an element, and “native”<input>
tags are elements, too.
BLOCK selectMOD disabledMOD multiple ELEMENT optgroup ELEMENT option MOD disabled MOD selected
Select boxes don’t really need labels, and anything else here is more or less similar to a normal select box control. Technically, we can reuse the existing<select>
tag with all of its structure. Note that both theselect
block and itsoption
element have adisabled
modifier. These aredifferent modifiers: The first one disables the whole control, while the second one (being a perfect example of an element modifier) disables just an individualoption
.
Try to find more examples of blocks in your web projects. Classifying things according to BEM takes some practice. Feel free to share your findings, orask the BEM team your questions!
Let Your CSS Speak Out Loud
Perhaps you’ve heard a lot about BEM as a way to optimize CSS and are wondering how it works?
As mentioned, BEM uses CSS class names to store information about blocks, elements and modifiers. With a simple naming convention, BEM teaches your CSS to speak, and it adds meaning that makes it simpler, faster, more scalable and easier to maintain.
BEM Naming Conventions For CSS
Here are the prerequisites:
- Keep the names of blocks, elements and modifiers short and semantic.
- Use only Latin letters, dashes and digits.
- Do not use underscores (
_
), which are reserved as “separator” characters.
Block containers get a CSS class of a prefix and a block name:
.b-heading.b-text-input
Thatb-
prefix stands for “block” and is the default in many BEM implementations. You can use your own — just keep it short. Prefixes are optional, but they emulate much-anticipated (and missing!) CSS namespaces.
Element containers within a block get CSS classes consisting of their block class, two underscores and the element’s name:
.b-text-input__label.b-text-input__text-field
Element names do not reflect the block’s structure. Regardless of nested levels within, it’s always just the block name and the element name (so, never.b-blockelem1elem2
).
Modifiers belong to a block or an element. Their CSS class is the class name of their “owner,” one underscore and a modifier name:
.b-text-input_disabled.b-select__option_selected
For a “boolean” modifier, this is enough. Some modifiers, however, are key-value pairs with more than one possible value. Use another underscore to separate the values:
.b-heading_level_alpha
Modifier classes are used together with the block and element class, like so:
<div>BEM</div>
Why Choose BEM CSS Over Other Approaches
One Class To Rule Them All
CSS sometimes depends a lot on the document’s structure — if you change the structure, you break the CSS. With BEM, you can drop tag names and IDs from your CSS completely, using only class names. This mostly frees you from structural dependencies.
Specificity Problems Solved
Big chunks of CSS are hard to maintain because they keep redefining themselves unpredictably.
This issue is called CSS specificity. The original problem is that both tag names and element IDs change selector specificity in such a way that if you rely on inheritance (the most common thing to expect from CSS), then you can only override it with selectors of the same or higher specificity. BEM projects are least affected by this problem. Let’s see why.
Let’s say you have a table with these style rules:
td.data { background-color: white }td.summary { background-color: yellow }
However, in another component, you need to redefine the background of a particular cell:
.final-summary { background-color: green }
This wouldn’t work becausetag.class
always has a higher specificity than just.class
.
You would add a tag name to the rule to make it work:
td.final-summary { background-color: green }
Because BEM provides unique class names for most styles, you would depend only on the order of rules.
Bye-Bye Cascade?!
Nested CSS selectors aren’t fast enough in old browsers and can create unintended overrides that break the styles of other elements. Eliminating a lot of the cascade from CSS is possible with BEM. How is this possible, and why is it important? Isn’t the cascadesupposed to be there? Isn’t it the “C” in CSS)?
As you know,every BEM CSS class is unique and self-sufficient. It does not depend on tags or IDs, and different blocks never share class names. That’s why you need only a single class name selector to do the following:
- style a block container,
- style any block element,
- add style extras and overrides with a modifier.
This covers most of your styling needs, all with just one class selector. So, it’s mostly about single-class selectors now, and they are extremely fast. To apply a selector, the browser starts with an initial (broader) set of elements (usually determined by the rightmost part of a selector), and then gradually reduces the set by applying other parts until only matching elements remain. The more steps needed, the more time it takes, which is why you can hardly beat single-class selectors for speed.
CSS is rarely a performance bottleneck on small pages, but CSS rules must be reapplied with every document reflow. So, when your project grows, things will get slower at some point. According to usability science, 250 milliseconds is the perception limit for “instant.” The faster your selectors are, the more room you have to manoeuvre to keep that “blazing fast” feeling for your users.
So, no cascade?! Well, almost. In some cases, you might need two class names in a selector — for example, when a block modifier affects individual elements:
.b-text-input_disabled .b-text-input__label { display: none;}
The nice thing is that any rule that redefines this one will likely depend on another modifier (because of the unified semantics!), which means that specificity is still the same and only the rule order matters. Surely, we can invent more cases that require even more cascading (internal element dependencies, nested modifiers, etc.). While the BEM methodology allows for that, you’ll hardly ever need it in real code.
Absolutely Independent Blocks
If blocks depend on each other’s styles, how do we express that in CSS? The answer is, they shouldn’t. Each block must contain all styles necessary for its presentation. The overhead is minimal, but this ensures that you can move blocks freely within a page or even between projects without extra dependencies. Avoid project-wide CSS resets for the same reason.
This is not the case for elements because they are guaranteed to stay within their parent block and, thus, inherit block styles accordingly.
Alternative BEM Naming Conventions
A number of alternative BEM naming conventions exist. Which should we use? BEM’s “official” naming convention for CSS is not the only one possible.Nicolas Gallagher once proposed some improvements, and other adopters have, too. One idea is to use attributes to represent modifiers, and CSS prefixes aren’t “standardized” at all.
The biggest advantage of the syntax proposed by the team behind BEM is that it’s the one supported in open-source tools distributed by Yandex, which you might find handy at some point. In the end, the methodology is what matters, not the naming convention; if you decide to use a different convention, just make sure you do it for a reason.