CSS has a rich and powerful syntax that seems natural to developers. Diving in headlong however can quickly lead to a world of unintended consequences, tangled stylesheets, and an escalating specificity war.
I came across the idea of the BEM naming convention – Block, Element, Modifier – in Smashing Book #4 (Chapter 1, Modern CSS Architecture and Front-End Development). In essence, it guides us to conceptualize and code CSS as a collection of abstractions rather than a single monolith. We already do this in our OO development of course, so extending the idea to CSS is not a great stretch.
A little CSS can go a long way and the same holds true with the BEM convention. An investment of as little as 15 minutes in researching and learning the technique can have an immediate and lasting impact on your UI skills. Firstly though, here are a few other takeaways from Smashing Book #4, Chapter 1:
- Style sheets should start with the most generic rules and progress toward the least generic
- Rules for un-classed elements come before those for components and classed elements
- Start with the foundations, add structure, then components, then visual design
- Separate the 'structure' of a component from it’s 'skin'
- Keep specificity low at all costs, and use classes not ID’s
- Keep compound selectors short (the number of segments, not the actual names)
- Don’t qualify selectors unnecessarily with elements, e.g. use
The BEM convention comes from the team at Yandex in Russia. It is designed to give meaning to CSS so that it is more easily understood across large teams of developers. You can think of a BEM tree as an abstraction of a DOM tree.
Personally I have found BEM a useful habit to adopt on any project. When I browse a stylesheet or markup that I have written in the past, the little units of BEM remind me of how I once conceptualized the interface and the bigger picture comes flooding back. Here are the key things to know about BEM:
- A web page is made up of building 'blocks'. A block is an independent entity and should be able to exist anywhere on the page (at least from a technical standpoint). It may contain other blocks. Typical block names include page, footer, logo, search-bar
- 'Elements' are descendants of blocks and help make the block a whole. Unlike blocks, elements are context sensitive. They make sense only within their given block. For example, a search field may be an element of a search block
- 'Modifiers' are used in conjunction with blocks or elements to make slight adjustments to appearance or behavior. They indicate a different state or version of the block or element. For example, a button may have a modifier for disabled, and another for selected. Multiple modifiers may be applied to a given element or block
The BEM methodology manifests in a web page as classes that follow a common naming convention. There are a few variations floating around, but here is the one that feels most natural to me (and the Smashing guy).
- A block name is a simple class name such as
- An element name is appended to its block name, separated by two underscoress. For example,
- A modifier is appended to its block or element name, separated by two hyphens. For example,
Here is an example from Smashing:
<div class="widget widget--foobar"> <div class="media"> <img src="" alt="" class="media__img widget__thumbnail"> <div class="media__body"> <h1 class="widget__heading"></h1> <p> </p> </div> </div> </div>
From this simple bit of markup we can ascertain that:
- We have two different blocks: widget and media
- The widget block has two elements: a thumbnail and a heading
- The media block has two elements: an image and a body
- We are using a widget modifier: foobar
If you are a Twitter Bootstrap user then this method of abstracting components may seem familiar. Look at the Bootstrap code for a panel component, for example:
<div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Panel title</h3> </div> <div class="panel-body"> Panel content </div> </div>
The naming convention is quite different, but the fundamentals are similar. The panel component:
- Uses class names (not id’s)
- Includes blocks (e.g. panel)
- Includes elements (e.g. panel-heading)
- Element names are prefaced by their block name
- Includes modifiers (e.g. panel-default)
- Modifier names are prefaced by their block name
I find it useful to add my own vendor namespace for blocks, e.g. b-, or kp-. This helps to distinguish my blocks from other components at a glance.
If this quick tour of BEM raises more questions for you than answers, don’t fret it. As I said before, a little bit goes a long way. Put it in to practice and see how you go.