Welcome to Creitive Global

Let's start

Partner with us

biz@creitive.com

Work with us

office@creitive.com

Let's play with BEM.

In the world of web development, complex scripts and other development tools are all the rage and people are often not taking CSS as seriously as they should. It is often referred to as "just CSS", and it is considered to be simple and easy, even on more complex projects.

Put a class here, move an element a bit to the left, open the console, play for a while with the properties in developer tools, copy everything you've done and paste it wherever, because it's "just CSS". After 4-5 days of fiddling, the website is done, really done. Then after a couple of weeks, if you try to add a new feature or even a minor improvement, everything falls apart. If you remove one thing, another one breaks. Finally, you end up just adding new classes without removing the old ones, leaving them there just in case.

If you're looking for a set of principles that allow you to write smart, maintainable, and modular CSS code, there is a methodology which is somewhat of a holy grail for every developer who wants CSS to just be CSS. Dear reader, meet BEM.

Block-Element-Modifier is a methodology that helps you create reusable components. It is a pretty popular naming convention for classes in HTML and CSS, which helps developers better understand the relationship between HTML and CSS. BEM is modular, flexible and easy to learn. It is also often used with server-side tools in "backend" languages to more easily generate the appropriate markup, but that's out of scope of this article - the naming conventions are useful on their own.

This is our take on BEM.

About the naming conventions

As we all know, naming things is one of the two hard things in computer science. The main idea of BEM is to make naming CSS selectors as informative and clear as possible. It helps make development and debugging much easier, and it solves many problems which web developers are faced with.

// Block class example.
.block {}

// We use camelCase for multiple words.
.thisIsTheBlock {}

// Element class example.
//
// Separated from the block with a dash.
.block-element {}
.thisIsTheBlock-element {}

// Modifier class example.
//
// Separated from the block or element with two dashes.
.block-element--modifier {}
.thisIsTheBlock-element--modifier {}

Block

A block defines a namespace for elements and modifiers. Block is an independent page component which can be reusable and nestable so you can easily move stuff from one page to another without modifying the CSS or JS.

Both are independent and can stand alone. They could have an impact on the outer environment, which means if you need to set margin, padding or any other property what has an impact on rest of the website, you need to be very careful.

<!-- Independent and can stand alone. -->
<article class="article">
    <h1>Contact us</h1>
</article>
<section class="news">
    <!-- Independent and nested. -->
    <article class="article">
        <h1>Contact us</h1>
    </article>
</section>

Element

An element's name is always defined by its block's parent.

Let's style a title in an article. We will show a few different HTML examples to see the correct and the wrong way.

In this markup we don't have a class on the title, so that means we need to style it through its parent. We need to select the h1 tag and that means we've created a nested selector.

<!-- Wrong. -->
<article class="article">
    <h1>Contact us</h1>
</article>
// Wrong.
.article h1 {
  font-size: 22px;
}

Let's add a class title on the h1 tag... But... What if we have already have the class .title somewhere else, maybe on the contact page or wherever.

<!-- Wrong. -->
<article class="article">
    <h1 class="title">Contact us</h1>
</article>
.title {
  font-size: 22px;
}

// A `title` class declared elsewhere in the code.
.title {
  font-size: 26px;
}

The probability to mess up selectors and get lost in the magic/madness of cascading CSS system is > 99%. How many times has this happened to you:

Say, let's nest .article .title { font-size: 22px; }. You refresh the browser and it's still not working. Hmm... You open developer tools and you see some selector from another page which overrode your code. .someBlogPage .title { font-size: 28px; } I know, I'll put an !important there. Whoops.

<!-- Wrong. -->
<article class="article">
    <h1 class="title">Contact us</h1>
</article>
.title {
  font-size: 22px;
}

.article .title {
  // Need this important because I didn't know what to do.
  font-size: 22px !important;
}

// A `title` class declared elsewhere in the code.
.title {
  font-size: 26px;
}

.someBlogPage .title {
  font-size: 28px;
}

Finally works! :)

We saw some wrong examples, now let's see the magic of BEM and let's meet the smart element.

In this example, article is the block, and article-title is the element which belongs to that block.

<!-- Correct. -->
<article class="article">
    <h1 class="article-title">Contact us</h1>
</article>
.article > .article-title {
  font-size: 22px;
}

The element cannot be independent (we tried that in the previous examples), and it works as intended only in the block in which it belongs to. That means if you move the element from its block, article-title should not work.

<!-- Wrong. -->
<article class="article"></article>
<h1 class="article-title">Contact us</h1>

The element's name must be unique in the scope where it lives, and it is separated from the block with a dash. e.g. article-title.

Block element relationships and mixing it up

Let's build a news section. This section has three articles and each article has a title, a short description and a "read more" link.

<section class="news">
    <article class="news-article">
        <h1 class="news-title">News</h1>
        <p class="news-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="news-link">
            Read more >
        </a>
    </article>
    <article class="news-article">
        <h1 class="news-title">News</h1>
        <p class="news-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="news-link">
            Read more >
        </a>
    </article>
    <article class="news-article">
        <h1 class="news-title">News</h1>
        <p class="news-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="news-link">
            Read more >
        </a>
    </article>
</section>

This is good class naming, and it follows the principles of BEM. But what if the news section has its own title, lead, link etc?

Will it be better if each of the articles are a block instead of an element? Or maybe it can be a block and an element at the same time?

By combining several BEM entities, we can create new semantic components based on already existing ones, which is one of the most powerful things in BEM.

<section class="news">
    <h1 class="news-title">News</h1>
    <p class="news-lead">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    </p>
    <article class="news-article article">
        <h1 class="article-title">News</h1>
        <p class="article-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="article-link">
            Read more >
        </a>
    </article>
    <article class="news-article article">
        <h1 class="article-title">News</h1>
        <p class="article-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="article-link">
            Read more >
        </a>
    </article>
    <article class="news-article article">
        <h1 class="article-title">News</h1>
        <p class="article-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="article-link">
            Read more >
        </a>
    </article>
    <a href="#" class="news-link">See all</a>
</section>

Modifiers

Modifiers can be inserted in either a block or an element. We use them when a block or an element need to be styled just a bit differently.

Modifier names are formed by combining a block's or an element's name with two dashes and a suffix. e.g. article--featured. If this suffix has more than one word, we use camelCase such as article--extraFeatured. A modifier cannot sit alone on an HTML tag, like <article class="article--featured"></article>.

Let's assume that the second article is a featured one, or in someway important to us, and we want to highlight it without disrupting the other articles.

This article will have a different color, a bigger button and let's say a bigger title.

<section class="news">
    <h1 class="news-title">News</h1>
    <p class="news-lead">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    </p>
    <article class="news-article article">
        <h1 class="article-title">News</h1>
        <p class="article-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="article-link">
            Read more >
        </a>
    </article>
    <article class="news-article article article--featured">
        <h1 class="article-title article-title--featured">News</h1>
        <p class="article-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="article-link article-link--featured">
            Read more >
        </a>
    </article>
    <article class="news-article article">
        <h1 class="article-title">News</h1>
        <p class="article-lead">
            Lorem ipsum dolor sit amet, consectetur adipisicing elit.
        </p>
        <a href="#" class="article-link">
            Read more >
        </a>
    </article>
    <a href="#" class="news-link">See all</a>
</section>

A block modifier can affect elements but it's recommended to avoid this because of nesting. If an element depends on a block, it is quite usual that an element is affected by its block's modifier.

<article class="article article--featured">
    <h1 class="article-title">News</h1>
    <p class="article-lead">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit.
    </p>
    <a href="#" class="article-link">
        Read more >
    </a>
</article>
// Affected by the block's modifier.
.article--featured .article-link {}

Global modifiers

You've probably used global modifier classes such as hidden, visible... In our company, they are not welcome. Let's hide an article with a global modifier.

<article class="article hidden">Contact us</article>
.hidden {
  display: none;
}

// Because of cascading we still see the article.
.article {
  display: block;
}

This way you need to track where you've included the global class, or if you don't want to do that, you need to add an !important. Sometimes, the hidden block requires a different property, such as a z-index which works only with certain position properties - relative and absolute. It's not good to have these properties on a global class because that stuff affects the block itself and then you need to override properties.

Welcome to hell!!!

<article class="article hidden">Contact us</article>
// Because of cascading we need `!important` here.
.hidden {
  position: absolute !important;
  z-index: -1 !important;
  display: none !important;
}

// Qualified selector because we need visibility instead of display.
.article.hidden {
  // Just in case.
  visibility: hidden !important;
  display: block !important;
  position: relative !important;
}

Ok, why not simply put the modifier to the block? We know that a modifier is dependent of a block or an element so we'll for certain know that they go together in one file.

Now we have control of them, isn't that great :).

<article class="article article--hidden">Contact us</article>
.article {
  display: block;
}

.article--hidden {
  display: none;
}

State modifiers, binding with JS

What if we want to animate some block or element or change their appearance from JavaScript?

Let's disable a button on click.

<button class="button">Click me</button>
.button {}

// Qualified selector.
.button.disabled {
  cursor: not-allowed;
}
$('.button').on('click', function () {
  $(this).addClass('disabled');
});

The problem appears when we want to remove this button. How will we know that the button is connected with JavaScript unless we go and search that class in all files?

Isn't it simpler to have some rule for elements which are connected to JavaScript? Maybe a js prefix?

And wouldn't it be better to add a better modifier instead of a global? button--disabled or even better, some prefix so we could know where the modifier class is coming from, for example is.

We have some rules:

  • Always bind elements with a js prefix in the class name, e.g. js-button, so we can know that the element has some connection to JavaScript.
  • If adding a class from JavaScript on some element, always use an is prefix, followed by a dash and a modifier, e.g. is-button--disabled.
<button class="button js-button">Click me</button>
.button {}

.is-button--disabled {
  cursor: not-allowed;
}
$('.js-button').on('click', function () {
  $(this).addClass('is-button--disabled');
});

CSS is considered to be easy. But the only thing that is easy, is to make a mess out of it. Fortunately, it doesn't take much to make it right. Take some time to learn BEM. You will end up with reusable and maintainable code that can easily be read and understood by others and your future self (trust us on this one).

Insights

Explore all