BEM Class Names Give Front-End CSS a Naming Contract That Ends Selector Fights
BEM International Naming Conventions in Front-End Development: Stop CSS From Fighting
Start with a “disaster case”
Have you ever been in this situation:
You write a
.btnstyle for a button and feel great. The next day, a colleague writes a.btnin their own module with totally different styles. The two.btnclasses meet on the page, CSS cascade rules start “fighting,” and the button ends up looking like a mess. The two of you stare at the screen, dumbfounded: whose fault is this, anyway?
This is the classic scene caused by CSS naming chaos. And BEM is the “peace treaty” that ends it.
What is BEM?
BEM is the abbreviation for Block, Element, and Modifier. It was proposed by the Russian company Yandex and is a CSS class-naming methodology.
Its core idea is simple: break the page into independent component blocks, and use one unified naming rule so every class name announces what it is.
Three roles, each doing its job
🧱 Block — an independent component
A Block is an independent, reusable component on the page. It does not depend on anything else and works fine on its own.
.header { }
.menu { }
.button { }
.card { }
Analogy: A Block is like a “wheel” in a set of LEGO bricks. It is complete by itself and does not need to attach to anything.
👶 Element — a part of a Block
An Element is a child part of a Block. Outside the Block it has no meaning. Use double underscores __ to connect the Block and the Element.
.menu__item { }
.card__title { }
.button__icon { }
.search-form__input { }
Analogy:
menu__itemis “one item in the menu.” It was born to belong tomenu; take it out alone and no one knows what it is for.
🎨 Modifier — a state or variant
A Modifier describes a Block or Element's different state, appearance, or variant. Use double hyphens -- when naming it.
.button--primary { }
.button--disabled { }
.menu__item--active { }
.card--dark { }
Analogy:
button--disabledis “the disabled button.” It is still a button, just in a different state.
The complete formula at a glance
.block { }
.block__element { }
.block--modifier { }
.block__element--modifier { }
Remember this formula and you can go anywhere without fear.
Hands-on practice: a card component
Here is a complete example:
<div class="card card--featured">
<h2 class="card__title">Featured Product</h2>
<p class="card__description">This is a product description.</p>
<button class="card__button card__button--primary">Buy Now</button>
</div>
/* Block */
.card {
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
/* Block Modifier */
.card--featured {
border-color: #ff6b6b;
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.2);
}
/* Elements */
.card__title {
font-size: 18px;
margin-bottom: 8px;
}
.card__description {
font-size: 14px;
color: #666;
}
.card__button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Element Modifier */
.card__button--primary {
background-color: #ff6b6b;
color: white;
}
See, just by looking at the class names you already know:
cardis the main componentcard__titleis the title inside the cardcard--featuredis the “featured” version of the cardcard__button--primaryis the primary-colored button in the card
Class names speak for themselves. No comments needed.
Why is BEM so good?
| Advantage | Description |
|---|---|
| Avoids style conflicts | Every class name has a unique “identity,” so they don't overwrite each other |
| Self-documenting | The class name reveals structure and relationships; newcomers get it immediately |
| Highly reusable | Blocks exist independently; you can drag them into any page |
| Team-friendly | Unified rules mean nobody has to guess someone else's naming habits |
| Low specificity | All single-level class selectors, no deep nesting; better performance and easier to override |
Some best practices
- All lowercase with hyphens between words:
search-form✅,searchForm❌ - No nested element names: don't write
card__body__text; just usecard__text - Modifiers can't be used alone:
card--darkmust appear together withcardin the HTML - Avoid deep CSS nesting: BEM encourages targeting with class names instead of selectors like
.card .body .text - Preprocessors make it more comfortable: with Sass's
&you can write a lot fewer repeated prefixes
.card {
padding: 20px;
&__title {
font-size: 18px;
}
&__button {
padding: 8px 16px;
&--primary {
background: #ff6b6b;
}
}
}
BEM's “small downsides”
Of course, BEM is not perfect:
- Class names tend to be long:
navigation-menu__item--activeis tiring to type - HTML is a bit redundant: one element may need several class names attached
- Not a silver bullet: for very small projects, it can feel like killing a chicken with an ox-cleaver
But overall, in team collaboration and medium-to-large projects, the sense of order BEM brings far outweighs its “typing cost.”
Final words
BEM is essentially a convention. It doesn't force you to do anything; it just tells you: if everyone follows the same naming rules, the CSS world will be much more peaceful.
Next time you are about to write a .btn, think about it: which Block does it belong to? Does it have a special Modifier? Once you answer those, your CSS code will go from “a pile of loose sand” to “a well-trained army.”
Naming is one of the two hardest things in programming, and BEM at least solves half of it. 😉