Naming is one of the hardest parts of CSS at scale. A good convention makes class names predictable, self-documenting and conflict-free, so any developer can read the HTML and understand the structure. BEM is the most widely used.
What BEM is
BEM stands for Block, Element, Modifier. A block is a standalone component (<code>card</code>). An element is a part of it, joined with two underscores (<code>card__title</code>). A modifier is a variant, joined with two hyphens (<code>card--featured</code>).
.card__title--large- Block
card - Element (__)
title - Modifier (--)
large
<div class="card card--featured"><h3 class="card__title">Title</h3><p class="card__text">Body</p></div>.card{background:#fff;border:1px solid #e2e8f0;border-radius:10px;padding:16px}
.card--featured{border-color:#2563eb;box-shadow:0 6px 18px rgba(37,99,235,.15)}
.card__title{margin:0 0 6px}
.card__text{margin:0;color:#64748b}Why BEM works
Every class is a single, flat class selector — so specificity stays low and equal. Names are unique and self-describing, so there are no accidental conflicts and the HTML reads like documentation. You never need to nest selectors to scope styles.
- .card .title { }
- High, uneven specificity
- Breaks if structure changes
- Hard to override
- .card__title { }
- Flat, equal specificity
- Independent of nesting
- Easy to override
BEM and utility classes together
Modern projects often combine BEM components with utility classes (single-purpose helpers like <code>.mt-4</code> or <code>.text-center</code>). BEM describes components; utilities handle one-off spacing and tweaks. Both stay low-specificity.
.cardTitle, .card-title, .CardTitle.card__title /* one consistent convention */Inventing inconsistent names (.cardTitle, .card-title, .card_title) across a codebase, causing confusion and duplicate styles. Pick one convention and stick to it.
Adopt one naming convention (BEM is a safe default) project-wide. Keep blocks reusable, name by purpose not appearance (.btn--primary, not .btn--blue), and combine with utility classes for one-offs.
Take a card component and rewrite its classes in BEM: a card block, card__title and card__text elements, and a card--featured modifier. Notice every selector is a single flat class.
1. In BEM, what joins an element to its block?
2. What does a modifier (--) represent?
3. Why does BEM keep specificity low?
4. Best naming practice?
- BEM = Block, Element (__), Modifier (--) for predictable names.
- Every BEM class is a flat selector, keeping specificity low and equal.
- Names are self-documenting and conflict-free — no nesting needed.
- Name by purpose, not appearance, and combine with utility classes.