Quantcast
Viewing all articles
Browse latest Browse all 54

Fifty Shades of BEM

As a development concept becomes popular, it is common to witness programmers forking it to fit various workflows and habits. This is resulting in a very fragmented landscape of implementations. It is happening to BEM at this very moment, and I myself have experimented with multiple flavors of it in the past few months.

This blog post has nothing to do with E. L. James’ book Fifty Shades of Grey, but I thought it would be a pretty catchy title. Sorry, folks: no erotic content here (although some developers might find CSS code quite sexy when written with the BEM methodology).

Image may be NSFW.
Clik here to view.
BEM

BEM (for Block-Element-Modifier) is a more and more commonly used approach to architect our CSS. If you haven’t heard of it yet, I distilled some information about this concept in a previous blog: Please Respect the Global CSS Namespace (you’ll find plenty of resources about BEM at the bottom of this previous post).

I have had the chance to experiment with it for the last 6 months on sizable projects and I came across many different ways of implementing it.

Note that “BEM” also references to a whole way of building your front-end with CSS, JavaScript and BEMHTML using the BEM Tools. I will not cover that part and focus on how to apply the methodology to our CSS.

Building a Navigation Menu With BEM

One of the most noticeable upsides of applying BEM in our code is that reading the CSS (without knowing what the HTML looks like) makes much more sense than with any other technique. Let’s say we’d like to build a simple navigation menu. The way BEM decomposes a selector name into easily identifiable parts goes as follows:

  • Block (e.g.: navigation)
  • Element (e.g.: item)
  • Modifier (e.g.: active)

One of the constructs useful with BEM is the Completely Independent Block (CIB): a self-sufficient module that should be portable in as many contexts as possible, with its own set of classes. BEM makes it easy to decompose a component into multiple parts, as when reading this code you’ll know exactly what is supposed to be going on:

.navigation {}
.navigation .item {}
.navigation .item.active {}

Simple! But in this code lies a massive problem: children .item elements will inherit .navigation .item styles. To put it simply: if we nest a sub-navigation in our navigation, then the .subnavigation .item elements inherit styles from .navigation .item.

A quick fix would be to use a child selector in our CSS:

.navigation {}
.navigation > .item {}
.navigation > .item.active {}

Great! Using the above solution, styles will only apply on .item elements if they are directly nested in .navigation (and not bleed on .subnavigation .item, for example). But we now rely very heavily on a particular DOM structure, which makes our code very fragile and not really prone to evolve. Not so great, then. Also, .active is a pretty common class that involves many risks of collision.

BEM will help us solving both those issues by using low-level identifiers, while avoiding any risk of collision with other UI components:

.navigation {}
.navigation__item {}
.navigation__item--active {}

This notation makes it quite obvious as of how elements are related to each other. It is very clear to what the HTML structure will look like and at the same time, it gives quite a lot of HTML structure and semantic freedom. The implementation could have .navigation__item as a direct children of .navigation, but this is not mandatory. Also, if we nest a subnavigation component in there, we could name its items .subnavigation__item. Those won’t be affected by the styles in .navigation__item (solving the cascade problem).

One Concept, Multiple Implementations

BEM is mainly a concept, and its inventors (Yandex) do not try to enforce any specific implementation, notation nor file naming conventions to the developers. In fact, the word is: please do what works for you.

Developers heard the Yandex guys and came up with multiple ways of applying this concept within their CSS. Let’s go through the most popular notations and see how we got there.

Underscores and Meaningful Dashes

The first attempt to reach a BEM-like CSS approach was documented by Nicolas Gallager in his blog “About HTML semantics and front-end architecture”, and thoroughly described in Harry Robert’s blog: MindBEMding – getting your head ’round BEM syntax (in which he tries to sound cool).

It goes something like this:

component-name
component-name--modifier-name
component-name__sub-object
component-name__sub-object--modifier-name

It is really ugly, but when you get your head around how this notation works, it’s a real breeze.

I have started implementing it on the BBC Responsive News website and it looks like the Guardian is doing the same on their Responsive Website. I also implemented this notation in parts of the application when redesigning the platform I’m working for — and despite being ugly, it has always worked really well.

Montage goes CamelCase

In the Montage HTML5 framework, a recent discussion lead to some interesting naming conventions.

“Class names follow a org-Component and org-Component-childElement pattern. So for the progress bar it would be: montage-Progress and montage-Progress-bar. (…) If a class name represents a state or a variation, double dash is used.”

org-ComponentName
org-ComponentName--modifiername
org-ComponentName-subObject
org-ComponentName-subObject--modifiername

The funny thing is that Montage extended the concept by representing a child of a child via the classname, so we could have a .org-ComponentName-subObject-subChild identifier.

I personnaly find this notation much more pleasant than the first one. Nicolas Gallagher is now using it in his Suit CSS toolset.

For Google Closure

I work on a product we build using Google Closure. To try and match the JavaScript developers habits, we wanted to have a modifier name that matched the framework naming conventions.

What does Google Closure do when it comes to states? In Google Closure, the mouseover state is an event of the MOUSEOVER type. This helped defining our modifier naming convention: all caps! In our codebase, modifiers will be expressed as class-MODIFIER.

Outside of that small variation, we took a very similar approach to the Montage notation:

prefix-ComponentName
prefix-ComponentName-MODIFIERNAME
prefix-ComponentName-subObject
prefix-ComponentName-subObject-MODIFIERNAME

What does prefix stand for, you ask? As an additional layer of clarity, we started prefixing our class names like this:

  • p- Page specific (class applied on the body element), very useful for static pages where maintainability is not at stake — should be avoided in the application itself (e.g.: p-Homepage).
  • l- Layout, columning, wrappers and containers… (e.g.: l-Masthead, l-Footer)
  • c- For components (e.g.: c-Dropdown, c-Button…).
  • u- Utility classes — will probably never change, should never be overridden anywhere else in our code (e.g.: u-textCenter, u-clearfix…).
  • js- Hooks for JavaScript: should never appear in the CSS itself.

With these very descriptive naming conventions (inspired from Jonathan Snook’s SMACSS), we believe we will achieve a much more robust architecture, hopefully less prone to errors from developers messing with the cascade in unexpected ways. Time will tell, I guess.

It’s up to You, Really

If you want to try BEM tomorrow in your project, what naming convention should you adopt? It’s up to you, really.

To be honest, I’ve rarely seen (if present at all) the same naming conventions between two projects, but I’ve even seen a lot of projects with multiple naming conventions in the same codebase (you could tell when the code had been produced by looking at how the class were named). Naming can easily become a bloody free for all — be aware of this and make time for some housekeeping in your code to make sure there is at least some sort of consistency across the whole project.

What about you, do you use BEM (or a BEM-flavored notation)? If so, what is your preferred coding and naming style?


Viewing all articles
Browse latest Browse all 54

Trending Articles