Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Practice: converting a component to BEM

Let us put together everything from this chapter in one example. Refactoring means changing code without changing its behavior: the page looks the same, but the code becomes clearer. We will take a product card written "however it turned out" and convert it to BEM.

The original code

Here is the card in the shape it often has in old projects:

<style>
  #catalog div { padding: 12px; border: 1px solid silver; border-radius: 8px; max-width: 240px; margin-bottom: 8px; }
  #catalog div h3 { margin: 0 0 6px; font-size: 18px; }
  #catalog div span { color: seagreen; font-weight: bold; }
  #catalog div button { margin-top: 8px; padding: 6px 12px; border: none; border-radius: 6px; background: seagreen; color: white; }
  .sale { border-color: crimson !important; }
  .sale span { color: crimson; }
</style>
 
<section id="catalog">
  <div>
    <h3>Backpack</h3>
    <span>€40</span><br>
    <button>Buy</button>
  </div>
  <div class="sale">
    <h3>Tent</h3>
    <span>€72</span><br>
    <button>Buy</button>
  </div>
</section>

Notice: the second card has a red border, but its price stayed green — the .sale span rule lost to the selector with an id.

What is wrong here

  • The selectors depend on the catalog id: the card cannot be shown outside the catalog.
  • The styles are tied to tags: replace <h3> with <h2> and the styling is gone.
  • #catalog div hits any <div> that appears inside the card.
  • The modifier relies on !important and still did not recolor everything.

Step 1: finding the blocks

First we decide which parts are standalone. The card is the product block. The button appears all over the site — a separate button block. Its place in the card will be set by an element through a mix.

Step 2: elements and modifiers

BeforeAfterWhat it is
#catalog div.productblock
#catalog div h3.product__titleelement
#catalog div span.product__priceelement
#catalog div button.button and .product__buyblock and element (a mix)
.sale.product--salemodifier

The <br> is no longer needed: display: block on the price is enough.

The result

<style>
  .button { padding: 6px 12px; border: none; border-radius: 6px; background: seagreen; color: white; }
 
  .product { padding: 12px; border: 1px solid silver; border-radius: 8px; max-width: 240px; margin-bottom: 8px; }
  .product--sale { border-color: crimson; }
  .product__title { margin: 0 0 6px; font-size: 18px; }
  .product__price { display: block; color: seagreen; font-weight: bold; }
  .product--sale .product__price { color: crimson; }
  .product__buy { margin-top: 8px; }
</style>
 
<section>
  <div class="product">
    <h3 class="product__title">Backpack</h3>
    <span class="product__price">€40</span>
    <button class="button product__buy">Buy</button>
  </div>
  <div class="product product--sale">
    <h3 class="product__title">Tent</h3>
    <span class="product__price">€72</span>
    <button class="button product__buy">Buy</button>
  </div>
</section>

The cards look as before, but now the price in the sale card is really red. There is no id and no !important in the code, and the card can be placed anywhere on the site.

Common mistake

Renaming the classes but keeping nested selectors:

.catalog .product .product__title { margin: 0 0 6px; }
.catalog .product .product__price { color: seagreen; }

The names look like BEM now, but the specificity is still high, and the card still works only inside .catalog. Check the result of a refactoring: almost every selector should be a single class.

Thanks for reading!

Donate to the site — we work hard for you.