BEM Guidelines for component focused development

BEM has been around for a while now and has gathered a lot of support within the community. It provides a good structured approach to class naming but in many situations still leaves a lot of implementation decisions up to the developers interpretation. The following are the guidelines we have developed at Rareloop to adopt BEM in our front end builds.

This guide is written for my own personal reference but hopefully it might be useful for others also working with BEM.

Goal

The goal of outlining guidelines is to produce a predictable (and importantly, repeatable) output for a given situation. No matter who writes the code, it should all appear to have come from one voice.

Basics

BEM is a naming convention, composed of Blocks, Elements & Modifiers. It is particuarly useful when you’re aim is to create reusable components (which should be most of the time!).

Instead of relying on the cascading aspect of CSS, the relationship between blocks and elements are encoded in the element’s class. Blocks and elements are seperated by two underscores (__) and modifiers are seperated by two dashes (--).

/* The outer container */
.block

/* A sub element */
.block__element

/* A modified sub element */
.block__element--modifier

Specifics

To help illustrate some specific guidelines we’ll start with some basic markup for a news article teaser, using classes encoded with the above convention.

<article class="news-teaser">
    <a class="news-teaser__link" href="#">
        <img class="news-teaser__image" alt="..." src="...">
        <h1 class="news-teaser__title">News article title</h1>
    </a>
    <p class="news-teaser__summary">Summary of the article...</p>
</article>

Don’t nest blocks and elements in CSS

The naming convention is designed to remove the need for nesting within CSS.

/* Good */
.news-teaser {}
.news-teaser__image {}
.news-teaser__title {}

/* Bad */
.news-teaser {}
.news-teaser .news-teaser__image {}
.news-teaser .news-teaser__title {}

Don’t go overboard on nesting

Each classname should contain at most one block and one element.

Nesting in CSS can lead to specificity issues and one of the design goals of BEM is to remove the need for it. A common way people interpret BEM is to encode the entire structure of the markup into the classname, creating a form of breadcrumb. Do not do this! This tightly couples your styles to the specific markup. As in the example above, naming should only indicate a parent/child relationship, not any details on depth or intermediatory layers.

/* Good */
.news-teaser__image

/* Bad */
.news-teaser__link__image

Modifiers should be added in addition to the base class

A modified version of a class should never be used as a replacement for the base class. By garanteeing the base class is always present it makes it easier to combine multiple fine grained modifier classes at once and toggle modified state through JavaScript.

<!-- Good -->
<article class="news-teaser news-teaser--featured">

<!-- Bad -->
<article class="news-teaser--featured">

Primary/common styles must be defined in the base class and only those styles that deviate from these should be overwritten in the modified class.

.news-teaser {
    padding: 2em;
    text-align: left;
}

/* Good */
.news-teaser--featured {
    color: #bada55;
}

/* Bad */
.news-teaser--featured {
    padding: 2em;
    text-align: left;
    color: #bada55;
}

When using Sass, your modified class should not @extend your base class.

Modifiers must always come at the end of the classname

A single classname must not describe a child of a modified parent. This is an example of where the CSS cascade should be used.

/* Good */
.news-teaser--filter .news-teaser__title {}

/* Bad */
.news-teaser--filter__title {}

Use the cascade for template level specialisation

When blocks are placed inside one another, if a parent block requires the style of a child block to be altered (and a modified class is not appropriate), use the cascade for specialisation.

.page-header .news-teaser__title {}

A modified class for the child block would be considered inappropriate if the alterations where tightly scoped to the parent block and would not make sense out of context.

Organisationally, the CSS for these specialisations should be located with the styles for parent block, not with the styles for the child block.

/**
 * Good
 */

/* partials/_news-teaser.scss */
.news-teaser {}
.news-teaser__title {}

/* partials/_page-header.scss */
.page-header {}
.page-header .news-teaser__title {}

/**
 * Bad
 */

/* partials/_news-teaser.scss */
.news-teaser {}
.news-teaser__title {}
.page-header .news-teaser__title {}

/* partials/_page-header.scss */
.page-header {}

Aim for element agnosticism

This should allow the type of HTML elements to be changed on a case by case basis (e.g. <h1 class="news-teaser__title"> or <h2 class="news-teaser__title">).

This is useful as it abstracts the semantics of the document away from the visual style you define for each given component and its children.

Know when to use it, and when not to

This naming convention is great for components but don’t attempt to shoe-horn it into every aspect of a site. These guidelines do not prevent your CSS containing standard utility classes for more fundamental content styling or layout.

Non-name based conventions

Although not strictly related to BEM or the naming of classes, the following are guidelines that help once a the above is implemented.

Margins should not bleed outside their containers

When building a series of re-usable components it is important that they are self contained and do not impact the layout of surrounding elements. Blocks must not impose margins and must not allow its child elements to impose any margins.

Spacing between components is a higher level concern and often differs on a case by case basis, therefore margins should be applied at a template level.

Blocks for layout

Following on from the previous point, a common pattern found on many sites is a grid of tiled blocks with consistent spacing between rows and columns. To achieve this, it is advised that a new block be created to manage the layout.

<ul class="news-teasers">
    <li class="news-teasers__item">
        <article class="news-teaser">...</article>
    </li>
    <li class="news-teasers__item">
        <article class="news-teaser news-teaser--featured">...</article>
    </li>
    <li class="news-teasers__item">
        <article class="news-teaser">...</article>
    </li>
</ul>

Vertical and horizontal spacing is then the sole responsibility of the news-teasers block and can easily be controlled across breakpoints.

In this scenario, the news-teaser block would also not be permitted to impose margin on its surroundings, so top-margin of the first row and the bottom-margin of the last row should be removed.

Whilst this might appear to add more markup than some purists may like, it maintains the seperations between each component and treats each as a black box where the inners are un-important. The news-teasers block is responsible for the layout of news-teasers__items which allows the news-teaser component to fill the available space.