blueSheep[dev];

Use Sass extend with BEM

Use Sass extend with BEM

Written on 2022-10-21 by Remco Kersten in frontend

Like2

If you often use the BEM architecture, you will probably have encountered this: you added the modifier class to an element, but forgot to add the element class. Your layout isn’t working as expected, and you’re wasting time figuring out what’s going wrong.

For this reason, some developers prefer to only add the modifier class in the HTML code, instead of adding both te element- and modifierclass. In this blog post I will show you how to achieve this with the extend rule in Sass.

⚠ Omitting the elementclass is not according to the official BEM rules. But rules can be broken.

A short recap to BEM

BEM stands for Block Element Modify. The goal of BEM is to make the structure of CSS clear, more maintainable and reusable.

According to BEM, your web page is made up of blocks with elements in it:

  • A block is a self-contained element that is used one or more times on your page. In the example below, the orange highlighted menu bar is a block.
  • An element is a part of a block. This does not stand alone, but is part of a block. In the example below the purple highlighted buttons in the menu bar are elements. Said are part of the menu bar.
  • A modifier changes something about an element. In the example below I have 4 elements, namely the buttons. However, I want some buttons to have a different color. I have created modifier classes which change the color. The default color of a button is darkgray, but I like to change the color of the second and fourth button. Check out the green highlighted buttons.

example-menubar.png

The associated HTML and CSS code according to the BEM method looks like this: Note here that the elements have two classes, namely the element class and a modifier class. After all, this is according to the BEM method.

<div class="menu">
   <div class="menu__item">Home</div>
   <div class="menu__item menu__item--purple">About me</div>
   <div class="menu__item">Projects</div>
   <div class="menu__item menu__item--green">Contact</div>
</div>
.menu {
  display: flex;
  justify-content: center;
  gap: 30px;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
  font-weight: 100;
}
.menu__item {
  padding: 5px 15px;
  border-radius: 5px;
  color: #ffffff;
  background-color: #2c3e50;
}
.menu__item--purple {
  background-color: #8e44ad;
}
.menu__item--blue {
  background-color: #2980b9;
}
.menu__item--green {
  background-color: #16a085;
}

Since this article is about sass I will show you what the sass code currently looks like and how the above CSS is generated:

$colors: (
  "purple": #8e44ad,
  "blue": #2980b9,
  "green": #16a085,
);

.menu {
  display: flex;
  justify-content: center;
  gap: 30px;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
  font-weight: 100;
  &__item {
    padding: 5px 15px;
    border-radius: 5px;
    color: #ffffff;
    background-color: #2c3e50;
    @each $name, $value in $colors {
      &--#{$name} {
        background-color: $value;
      }
    }
  }
}
  • .menu is the class for the menu (block)
  • .menu__item is the class for the menu buttons (elements)
  • At the beginning of the sass file is a map with different colors. For each color a modifier class is generated which changes the background of a menu button.

Omit elementclass if there is a modifier class?

So far a short recap about BEM with an example project. What if we add a modifier class, can we omit the element class? So as follows:

<div class="menu__item--purple">About me</div>

The answer is: no! The class menu__item--purple contains only the color. The other style properties are in menu__item. So we have to add both the element class and the modifier class following the BEM method:

<div class="menu__item menu__item--purple">About me</div>

However, since we can actually recognize from menu__item--purple that this is a menu__item, it might make sense to omit the elementclass.

Using the extend rule in Sass

Suppose you choose to omit the element class if a modifier class is present. How do you make sure that the modifier class still takes over the rules of the element class?

In the above sass file, a modifier class is created for each color. By now indicating that this is an extension of menu__item, a selector is added for the relevant modifier class.

$colors: (
  "purple": #8e44ad,
  "blue": #2980b9,
  "green": #16a085,
);

.menu {
  display: flex;
  justify-content: center;
  gap: 30px;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
  font-weight: 100;
  &__item {
    padding: 5px 15px;
    border-radius: 5px;
    color: #ffffff;
    background-color: #2c3e50;
    @each $name, $value in $colors {
      &--#{$name} {
        @extend .menu__item;
        background-color: $value;
      }
    }
  }
}

Where previously the style of a button was only applied to elements with the class menu__item, they are now also applied to elements that have a modifier class:

.menu {
  display: flex;
  justify-content: center;
  gap: 30px;
  font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
  font-weight: 100;
}
.menu__item, .menu__item--green, .menu__item--blue, .menu__item--purple {
  padding: 5px 15px;
  border-radius: 5px;
  color: #ffffff;
  background-color: #2c3e50;
}
.menu__item--purple {
  background-color: #8e44ad;
}
.menu__item--blue {
  background-color: #2980b9;
}
.menu__item--green {
  background-color: #16a085;
}

Because of this, if an element has a modifier class, we can now remove the element class:

<div class="menu">
   <div class="menu__item">Home</div>
   <div class="menu__item--purple">About me</div>
   <div class="menu__item">Projects</div>
   <div class="menu__item--green">Contact</div>
</div>