facebook

Blog

Stay updated

Let's see how to simplify the creation of CSS with the BEM methodology
How to simplfy CSS with BEM
Wednesday, September 04, 2019

What BEM is

Let’s start with basics: BEM is not a framework, but a methodology, a special way to write and organize the CSS code that I love to define as “BEM Philosophy”, a pun that explains the inner peace you can obtain through the use of this technique.

Do you remember about CSS Zen Garden? Although there’s nothing in common on a technological point of view about it, it’s the same principle to work on stylesheets with no need to risk a nervous breakdown. The modification of a CSS is similar to the neutralization of a bomb: you never know whether the modification you are going to make on a component, may cause the explosion of another one.

First things first: let’s start to analyze one of the most common problems deriving from CSS codification. How many times you will ever stylized a button and then you re-used it inside another code block and you lost the whole expected personalization?

Let’s look at this code example:

<main class="container">
    <button type="button" class="btn">
    ENTER
    </button>
</main>
     
<aside class="sidebar">
    <button type="button" class="btn">
    ENTER
    </button>
</aside>
/* CSS */
  
.container .btn {
           background: red;
           color: white;
           font-size: 15px;
           height: 50px;
           padding: 5px 10px;
     }

The button inside .container will be rendered as follows:

But look what happens when we move the button inside.sidebar

In this example, we used a descendant selector. The button changes its form, because the CSS properties are applied only when .btn is put inside the block .container. Inside any other different block, like .sidebar, therefore, it will take a different form.

It would be nice to have univocal components that can be moved from point A to point B in our layout and maintain them unchanged: well, this is finally possible thanks to BEM methodology!

Let’s see how: BEM stands for Block – Element -Modifier

  • .block : it represents the parent element and it can be inserted in other blocks, but it has to be independent from them;
  • .block__element : the element, it is dependent from the block;
  • .block—modifier : it is used to modify the basis style and it can be applied both on a block and on an element.

A class must be assigned to every element in the markup and IDs are not allowed. At first glance, the syntax might be not pleasant to see, but you have to get used to it.

This is a practical example, where .card represents the parent block and .card__title and .card__content are child elements related to it. The name of the block, from which the element depends, must be specified in the first part of the selector, ahead of the double underscore (__). Then the name of the element (semantic, if possible) itself must be inserted right after.

<div class="card" >
    <h1 class="card__title" >Hello World!</h1 >
    <p class="card__content" >Text... </p >
</div >

In this case, .card—red represents the Modifier of card and it replaces its background by default. The name of the Block, to which the Modifier must be applied, should be inserted ahead of the double dash (–) and after that it must be inserted the name of the Modifier itself.

<div class="card card--red">
    <h1 class="card__title">Hello World!</h1>
    <p class="card__content">Text... </p>
</div>

The related CSS is instead:

.card {
    background: white;
}
    .card.card--red {
    background: red;
}

Is it possible to nest the blocks?

The answer is yes! A classical example is a form positioned inside a .card block.

<div class="card">
    <h1 class="card__title">Contacts </h1>
    <p class="card__content">Text... </p>
         
    <form class="form-contact">
    <input type="text" class="form-contact__input">
    <textarea ows="10" class="form-contact__message"></textarea>
    <button class="form-contact__btn">SUBMIT</button>
    </form>
</div>
/* CSS */
    .form-contact { ... }
    .form-contact__input { ... }
    .form-contact__text { ... }

How to manage nested elements

When we choose selectors’ names, we always have to refer to the Block, with no need to follow the DOM structure. By doing so, we can move elements inside the block at taste, with no need to re-write the code from time to time. The example below should NOT be followed:

<div class="block">
    <header class="block__header">
    Hello
    <strong class="block__header__strong">World! </strong>
    </header>
</div>
  
<div class="block">
    <header class="block__header">
    <h1 class="block__header__title">
    Hello
    <strong class="block__header__title__strong">World! </strong>
    </h1>
    </header>
</div>
.block { ... }
.block__header { ... }
.block__header__title { ... }
.block__header__title__strong { ... }

This is the correct approach instead:

<div class="block">
    <header class="block__header">
    <h1 class="block__title">
    Hello
    <strong class="block__strong">World!</strong>
    </h1>
    </header>
</div>
/* CSS */
.block { ... }
.block__header { ... }
.block__title { ... }
.block__strong { ... }

How to use it with SASS

Using BEM together with SASS is really wonderful because, thanks to the use of the Nesting and the directive &, that allows us to obtain an interpolation with the name of the block, we have the opportunity to make some components, that can be easily moved from project to another, without problems. This is a classical example of a stylized button:

/* SCSS */
  
.btn {
    background: black;
  
    &__label {
        color: white;
    }
     
    &#{&}--red {
        background: red;
    }
    &#{&}--blue {
        background: blue;
    }
}

In this case, in addition to the directive & we used to define selectors of elements, we will use also the directive #{&} , which allows us to create a further interpolation of the name of the block. The compiled CSS would be then:

/* CSS compilato */
.btn {
    background: black;
  }
  .btn__label {
    color: white;
  }
  .btn.btn--red {
    background: red;
  }
  .btn.btn--blue {
    background: blue;
}

In addition, we can further divide our SCSS in many files, then insert everything in a single stylesheet through the directive @import of SASS. We will have a structure like this:

website /
    ├── scss /
    │   ├── style.scss
    │   ├── _header.scss
    │   ├── _footer.scss
    │   ├── _button.scss
    ├──
  
  
STYLE.SCSS
    @import header;
    @import footer;
    @import button;

How to use it with Bootstrap?

Even if the trend of recent years is to use frameworkless solutions, Bootstrap is still one of the most used tools: how can we use it with BEM then? We can proceed like that: we will not define the blocks size, we can define only the height if needed. In this case, we need to abstract the grid from the components and we should avoid adding classes to Bootstrap columns. This is a practical example:

<div class="row">
   <div class="col-md-6">
    <div class="block">
            <header class="block__header">
                <h1 class="block__title">
                    Hello
                    <strong class="block__strong">World! </strong>
                </h1>
            </header>
        </div>
    </div>
    <div class="col-md-6">
        <div class="block">
            <header class="block__header">
                <h1 class="block__title">
                    Hello
                    <strong class="block__strong">World! </strong>
                </h1>
            </header>
        </div>
    </div>
</div>

Decoupling components from the grid, we will have the possibility to substitute bootstrap with another framework or with CSS grid (in next article, we will talk about it)

What are advantages

  • better code maintainability;
  • possibility to create components, that can be used in other projects;
  • performance optimization: avoiding the use of descendant selector and assigning a class to any element, we don’t force the browser to make too many calculations.

What are the disadvantages

Obviously, all that glitters is not gold: in the real world, we need sometimes to compromise with BEM methodology. Especially when we need to make many reset on the elements, in fact, and selectors could be very verbose, in case we had Blocks with Modifiers and Elements that presents Modifiers in their turns. For example, the same button in some pages could have the shadow and in other pages it could have it not: to avoid the application of more Modifiers to the element, I tried to solve with three possible paths to be taken.

In the first one, the button could be defined as Block, and, in extreme situations, we will use an element instead of the modifier, in order to use the selector .activity-main__btn to obtain specific personalizations, as the application of the shadow.

<div class="activity-main activity-main--white">
       <button type="button" class="btn-main btn--red activity-main__btn"></button>
</div>

A second path could be to use “helpers” classes (to be clear, those that describe properties they are going to apply) without exaggeration, and we obtain then a markup as:

<div class="activity-main activity-main--white">
    <button type="button" class="btn-main btn--red shadow"></button>
</div>

the last option is to ask to the designer to modify the button, because it is not congruent to others on the website and avoid this problem…but this is another story.

Best practices

Theoretically: elements must not be moved from a block to another. For this reason, when you start a new project, it would be a good idea to create a styleguide, in order to define all blocks, elements and modifiers.

Practically: if we are asked for typical “last minute” modifications, we can easily move an element from a block to another one, with no fear to find it stylized in a different manner, and then we can optimize the code too.

Selectors name might appear fragmented, due to the use of dashes and underscores: we can solve this problem with the use of camel case. A .activity-main__title could become .activityMain__title then.

In my next article, I will write about CSS grid and we will see together how to use it together with BEM methodology.