In the BEM CSS naming methodology, what do "block", "element" and "modifier" mean, and how does each one appear in a class name?
answer
- component, part, variant
- the name carries the scope
- double underscore joins block to part
- double hyphen marks the variant
- modifier rides beside the base class
basics
~10 sBEM names classes after a block (a standalone component, .card), its elements (parts that exist only inside it, .card__title), and modifiers (variant flags, .card--featured). Two underscores mark an element, two hyphens mark a modifier.
solid answer
~40 sBEM stands for Block, Element, Modifier, and it encodes a component's scope directly in the class name because CSS itself has no scoping. A **block** is a standalone, meaningful piece of UI named for what it is, not how it looks: `.card`, `.site-search`. An **element** is a part that has no meaning outside its block, written `block__element` with two underscores: `.card__title`. A **modifier** is a flag that changes a block's or element's appearance or state, written with two hyphens: `.card--featured`, `.card__title--truncated`; it is added *alongside* the base class, never instead of it. Every rule is then a single class selector, so specificity is flat and source order decides conflicts. The element part stays flat no matter how deep the markup nests — `.card__title` even if the heading sits three `div`s down.
code
css · 5 lines.card { display: grid; gap: 0.5rem; }
.card__title { font-size: 1.25rem; }
.card__meta { color: #666; }
.card--featured { outline: 2px solid #b30; }
.card__title--truncated { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }go deeper
Be able to spell the three parts confidently — block, block__element, block--modifier — and say why the prefix exists at all: CSS has one global namespace, so the name carries the scope.
Explain the mechanics: element names are flat regardless of markup depth, every rule is a single class so specificity stays equal, and a modifier holds only the delta from the base rule.
Show judgment about where the boundaries fall — when a part earns promotion to its own block, why components must not own their outer geometry, and how mixes keep them context-free.
Own the enforcement question: a convention nothing checks decays, so be ready to discuss linting the class pattern, keeping one spelling across teams, and what the convention costs in rename churn.
## Why a naming convention exists at all CSS has exactly one global namespace. A selector written anywhere matches anywhere in the document, so two engineers who both write `.title` in two different stylesheets silently fight over the same elements. BEM — Block, Element, Modifier, originally from Yandex — answers that by putting the scope into the name itself: the class *is* the namespace. The whole methodology is a grammar for class names plus one structural rule (one class per rule). ## Block A block is a standalone, meaningful chunk of interface that would still make sense if you moved it somewhere else on the page: `.card`, `.menu`, `.site-search`, `.pagination`. Two naming disciplines matter here. First, name it for **what it is**, never for how it looks or where it sits — `.card`, not `.blue-box` and not `.sidebar-thing`, because the colour will change and the sidebar will move. Second, a block should not set its own external geometry (outer `margin`, `position`, a `width` that only fits one slot), because that hard-codes one context into a component meant to be reusable. ## Element An element is a part of a block that has no standalone meaning — a card's title, a menu's item, a form's submit row. It is written with the block name, two underscores, then the element name: ```css .card { } .card__media { } .card__title { } ``` Two things surprise newcomers. The element name is **flat**: it names ownership, not DOM depth, so a heading nested three levels inside the card is still `.card__title`, not a path through its ancestors. And the class is used as a **single class selector** — you write `.card__title { }`, not `.card .card__title { }`; the prefix has already done the scoping work that a descendant selector would otherwise do. ## Modifier A modifier is a flag that changes appearance, state or behaviour of the block or element it hangs off: `.card--featured`, `.button--ghost`, `.card__title--truncated`. It is applied as an extra class next to the base one: ```html <article class="card card--featured"> <h2 class="card__title">Release notes</h2> </article> ``` The modifier rule carries only the *difference* from the base, which is why both classes must be present. ## The two spellings The original Yandex syntax marks modifiers with a single underscore and optionally a value: `block__elem_mod_val`. The variant most teams use today — popularised by the getbem.com write-up — is the "two dashes" style: `block__elem--mod`. Both are legitimate BEM; what is not legitimate is mixing them in one codebase, because the delimiters are the only thing telling a reader which part of the name is which. ## What the grammar actually buys - **Readability from the markup alone.** Seeing `class="card__footer"` in a template tells you which stylesheet component owns it, without grepping. - **Flat specificity by construction.** Every selector is one class, so they all weigh the same and conflicts resolve by source order rather than by who nested deeper. - **Safe deletion.** Removing a component means removing one name prefix; nothing else in the sheet claims those names. - **Visible misuse.** A `card__title` appearing outside a `card` is an obvious defect to a reviewer, which a generic `.title` never would be. ## Mixes: putting a block inside another block Because blocks must not own their outer positioning, BEM uses a **mix** — two entities on one DOM node: ```html <ul class="feed"> <li class="feed__item"> <article class="card">…</article> </li> </ul> ``` or, collapsing the node, `<article class="card feed__item">`. The `card` class supplies the component; the `feed__item` class supplies the parent's layout slot. The card stays context-free and reusable. ## The mistakes reviewers look for Chaining element names (`card__body__title`); naming blocks after appearance; applying a modifier without its base class; and re-introducing descendant selectors such as `.card .card__title`, which throws away the flat specificity the naming already guaranteed.
- How do you decide whether something is an element of a block or a block in its own right?Ask whether it means anything outside its parent. A card's footer is meaningless alone, so it is `card__footer`. An avatar, a button or a badge is reusable elsewhere, so it is its own block — and where it sits inside a card, you mix the two classes on one node (`class="avatar card__avatar"`) so the card owns the placement and the avatar owns itself.
- Is the two-dashes syntax the only correct BEM?No. The original Yandex convention marks modifiers with a single underscore and supports key/value modifiers, as in `menu__item_state_active`. The two-dashes form `menu__item--active` is a later, more widely adopted variant. Either is valid BEM; mixing both in one codebase is not, because the delimiters are the only signal of which part of the name is which.
- Why does BEM insist a block should not set its own margin or position?Because those properties describe a relationship to a surrounding context, not the component. Baking them in means the block only fits one place. BEM pushes outer geometry onto the parent's element class — the mix pattern — so the same block drops into a sidebar, a grid cell or a modal without overrides.
Think of it as a filesystem path flattened into one word: the block is the folder, the element is the file inside it, and the modifier is a flag you pass alongside it rather than a different file.
saying these in an interview costs you the question
- Says the element class only works nested under the block selector
- Names blocks by appearance, like .blue-box or .left-column
- Applies a modifier class alone, without the base class
- Chains element names to mirror how deep the markup nests
- Treats block, element and modifier delimiters as interchangeable