BEM in CSS: the naming method that tames your classes

BEM structures your CSS classes into block, element and modifier to eliminate naming collisions and specificity creep.
6 min read
Believemy logo

On a project that keeps growing, CSS stylesheets almost always start out looking like a tidy garden, then slowly turn into a jungle: generic classes like .title, .button or .item start stepping on each other, a fix on one page silently breaks another, and eventually nobody dares touch the CSS without retesting everything. BEM exists precisely to avoid that scenario.

It is neither a framework nor a special CSS syntax: it is a class naming convention, designed so that a class name alone tells you the structure of the component it dresses.


Definition

BEM stands for Block, Element, Modifier. It is a CSS class naming methodology, popularized by the Yandex team, that organizes every class name around three ideas: the block, a standalone reusable component; the element, a part of the block that has no meaning outside it; and the modifier, a variant in appearance or state of the block or the element.

CSS
/* Block */
.card {
}

/* Element: belongs to the .card block */
.card__title {
}
.card__image {
}

/* Modifier: variant of the block */
.card--highlighted {
}

/* Modifier: variant of an element */
.card__title--large {
}

The syntax uses two underscores to connect a block to its element (card__title) and two dashes to connect a block or element to its modifier (card--highlighted). This regularity is not just an aesthetic detail: it is exactly what makes a class name readable without ever needing to open the HTML to understand what it does.


The problem BEM solves

Without a convention, a medium sized CSS project quickly develops two classic diseases. The first is naming collisions: two developers each create a .title class for different needs, and the second definition silently overrides the first according to the rules of the Cascade. The second disease is Specificity escalation: to fix a style that does not apply as expected, someone adds a more precise selector, or worse, an !important, which makes the next fix even harder.

BEM attacks both problems at the root. Since every BEM class is a unique, explicit name rather than a generic Class selector combined with descendant selectors, specificity stays flat: a single class is almost always enough, with no nested selectors required. And because the block name systematically prefixes its elements, two different components can almost never collide, even on a project spanning hundreds of CSS files.


A concrete example

Take a fairly typical search component: a text input, a button, and a compact variant used in the site header.

CSS
.search-form {
  display: flex;
  gap: 8px;
}
.search-form__input {
  flex: 1;
  padding: 8px;
}
.search-form__button {
  padding: 8px 16px;
}
.search-form--compact {
  gap: 4px;
}
.search-form--compact .search-form__input {
  padding: 4px;
}

The matching HTML reads almost like a sentence, without needing to consult the stylesheet to understand the hierarchy:

HTML
<form class="search-form search-form--compact">
  <input class="search-form__input" />
  <button class="search-form__button">Search</button>
</form>

A new developer joining this project understands at a glance that .search-form__input necessarily belongs to the .search-form block, and that the compact variant adjusts spacing without duplicating the base rules.


Where to draw the line between block and element

The main difficulty with BEM is not its syntax, which becomes mechanical once learned, but the decomposition: should this be a new block or just one more element? The most reliable rule is to ask whether this fragment of HTML would still make sense copied elsewhere in the project, isolated from its original context. If yes, it is probably a block in its own right. If the fragment only exists and only makes sense stuck to its parent, like an icon inside one specific button, it is an element.

SituationRecommended choice
A product card reused across several pagesBlock (.product-card)
The title inside that cardElement (.product-card__title)
A grayed out variant of the card when out of stockModifier (.product-card--out-of-stock)
A generic button used in ten different contextsIndependent block (.button), not an element of each parent


BEM compared to other approaches

BEM is not the only answer to the problem of class collisions. CSS modules, CSS-in-JS solutions, and even native Native CSS nesting recently landed in browsers all offer other ways to scope a style. The difference is that BEM requires no build tool at all: it is a pure writing discipline, applicable in any project, even the smallest one, without a preprocessor or compiler.

This lack of dependency explains why BEM remains widely used more than a decade after it was popularized, including on projects that also rely on more recent tooling. Our HTML and CSS course introduces this method from the very first practical projects, so structuring class names becomes a habit before a project ever grows large.


Common pitfalls

Good to knowA frequent pitfall is chaining elements as if they were nested in the name: .card__header__title. BEM only allows for a single level of element per block. If an element itself has a complex sub-structure, the right move is either to treat it as its own independent block, or to keep a flat name like .card__title, without stacking double underscores.

A second pitfall is piling up modifiers to the point of recreating, in a different form, the same class explosion BEM was meant to prevent. If a block accumulates ten different modifiers that combine with each other, it is often better to rethink the split into several simpler blocks rather than keep stacking variants.


FAQ

QuestionDoes BEM require Sass or a preprocessor?

No, BEM works just as well in plain CSS as with a preprocessor. Sass simply makes writing nested class names faster thanks to the ampersand &, but the convention itself does not depend on any tool and existed before preprocessors became common in web projects.

QuestionCan BEM be combined with Flexbox or Grid for layout?

Yes, without any issue. BEM only governs class naming, not the CSS properties applied to them. A BEM block can perfectly well be a container using display: flex or display: grid, since the naming methodology and the layout technique answer two completely different questions.

QuestionDoes BEM slow down writing HTML because of longer class names?

A little, at first glance, but that cost pays for itself quickly. Longer but explicit class names, such as .search-form__button rather than .btn, save hours of digging through a browser inspector trying to figure out which component a style actually belongs to, especially on a project picked up by someone else months later.

Related terms

Discover our hTML and CSS glossary

Browse the terms and definitions most commonly used in HTML and CSS development.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.