BEM block, naming & nesting

aventic picture aventic · Mar 21, 2014 · Viewed 28.9k times · Source

I am trying to wrap my head around BEM naming convention. I am stuck at this. I may misunderstanding something, lets see.

I have a sidebar nav and a content nav.

My sidebar nav looks like this

<div class="sidebar">
    <ul class="sidebar__nav">
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
    </ul>
</div>

And my content nav looks like this

<div class="content">
    <ul class="content__nav">
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
    </ul>
</div>

Now I will run into a problem if I style .nav__item, they occur in both my navigations and should not have the same styling. Should I do some nesting here, or am I naming my blocks and elements wrong?

Nesting example in CSS:

.content__nav .nav__item { background: Red; }

Or should I name it like this:

<li class="content__nav__item"><a href="#" class="content__nav__link">LINK</a></li>

Can you help?

Answer

zzzzBov picture zzzzBov · Mar 21, 2014

There are a number of variants on how to write BEM classes, so be aware that are multiple competing standards. It started as a set of loose guidelines. Since posting this answer, Yandex has significantly overhauled their official standard (it's quite an improvement). The version of BEM I use is based heavily from an article by Nicolas Gallagher.

At this point I use "Atomic OOBEMITLESS", which is really just a way of saying that classes are modular and namespaced, selectors have low specificity, and states may be toggled with classes which allows CSS to be scaled, on top of a CSS preprocessor to make the code more concise and expressive.

All that said, I will be using the following BEM standard:

  • hyphenated class names as blocks:
    foo-bar
  • block name followed by __ followed by hyphenated class names for elements:
    foo-bar__fizz-buzz
  • block or element names followed by -- followed by hyphenated class names for modifiers:
    foo-bar--baz, foo-bar--baz__fizz-buzz, foo-bar__fizz-buzz--qux

BEM short form: block-name__element-name--modifier-name


You have three different blocks in your examples:

  1. sidebar, which has a sidebar__nav element
  2. content, which has a content__nav element
  3. nav, which has nav__item and nav__link elements

The sidebar and content blocks appear to be variations on the same block, and could be represented as .region.region--sidebar and .region.region--content.

The nav block is implicit on the ul element, and you should make it explicit:

<ul class="nav"><!-- could be content__nav or sidebar__nav as well if you choose -->
    <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
    <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
</ul>

Once you've specified that the ul element is a nav block, it makes sense to have the nav block be modified:

<ul class="nav nav--content">
    <li class="nav__item nav--content__item"><a href="#" class="nav__link nav--content__link">LINK</a></li>
    <li class="nav__item nav--content__item"><a href="#" class="nav__link nav--content__link">LINK</a></li>
</ul>

Once you've set up the CSS classes, styling all nav__item elements is simply:

.nav__item {
    ...styles here...
}

and overriding those styles for the content nav__item elements is:

.nav--content__item {
    ...styles here...
}