loading...

Explain CSS BEM Structures Like I'm Five

davedodea profile image Dave O'Dea ・1 min read

I) What are they?
II) How and why are they used?
III) What are some recommend resources for further learning?

Cheers,
Dave

Discussion

pic
Editor guide
Collapse
isaacdlyman profile image
Isaac Lyman

In traditional webapps (i.e. webapps built before CSS encapsulation was invented), every CSS rule is shared by the entire app. This creates a few problems:

1) the "acupuncture effect": you modify a style on a button on page A, and suddenly an input on page C is broken. If you've worked on a large web project you've probably got a few gray hairs because of this.
2) fragmentation: one developer uses really explicit class names, e.g. .button-on-the-checkout-page-underneath-the-subtotal, another uses brief class names, e.g. .btn, and yet another uses IDs instead of classes (shudder).
3) fighting the cascade: you write some styles for an element, save, reload, and none of the styles have any effect. You inspect the page and someone else's styles have greater specificity than yours. You have to invent a random way to add specificity to your rule so that your styles will show up, without also wrecking every other element that uses the old styles.

BEM is not a plugin, a library or a framework. It's a set of rules you can adopt to make CSS easier to work with in your project. It stands for "Block, Element, Modifier" and, in short, it gives you the following rules:

1) Every CSS selector should use a single unique class name, not a tag, an ID, or an attribute.
2) Every element in your app should have its own special class.
3) An app is a set of components (known as "blocks" in BEM), and each component has several HTML elements (the E in BEM). Sometimes elements look different depending on the state of your app (different states are "modifiers" in BEM).
4) CSS classes are constructed like this: block__element--modifier. Hyphens are used for multi-word blocks, elements, or modifiers.

So a component in an AngularJS app that follows BEM could look like this:

<div class="week-calendar">
  <div class="week-calendar__header"></div>
  <div class="week-calendar__body"></div>
  <div class="week-calendar__actions">
    <button class="week-calendar__save"
      ng-class="{ 'week-calendar__save--saving': ctrl.saving }">
      Save
    </button>
  </div>
</div>

And the stylesheet would look like this:

.week-calendar { height: 200px; width: 300px; }
.week-calendar__header { height: 40px; }
.week-calendar__body { height: 140px; }
.week-calendar__actions { height: 20px; }
.week-calendar__save { background-color: green; cursor: pointer; }
.week-calendar__save--saving { background-color: gray; cursor: default; }

Or, with a preprocessor like SASS:

.week-calendar {
  height: 200px;
  width: 300px;

  &__header { height: 40px; }
  &__body { height: 140px; }
  &__actions { height: 20px; }
  &__save {
    background-color: green;
    cursor: pointer;

    &--saving {
      background-color: gray;
      cursor: default;
    }
  }
}

When you use BEM, you can look at any class name and know what element it applies to. Specificity never gets out of control, because each element has its own class. And styles meant for specific components won't affect other parts of the app. If you don't have access to CSS encapsulation via a modern solution like Vue, React, CSS Modules, or Angular 2+, this is a great way to keep your style sheets sane.

Collapse
miku86 profile image
miku86

Hey Isaac,

thanks for your explanation,
especially for the part about the traditional problems.

Collapse
craser profile image
Chris Raser

That's a great explanation.

Collapse
caiorcferreira profile image
Caio Ferreira

Great explanation, thanks!
Just a question, from a readability point of view, you'd say that it is valid to use even in React or other frameworks?

Collapse
isaacdlyman profile image
Isaac Lyman

That's a hard one. Last I checked, the "official" solution for styling React apps is CSS-in-JS, which uses the HTML style attribute, which makes BEM irrelevant. However, if you decide to style your app with traditional CSS files (or <style> tags), then yes, BEM is valid.

As far as other frameworks, it depends. Angular 2+ and Vue (with Single File Components) have CSS encapsulation, so BEM, while still valid, is probably solving a problem you don't have.

There are a few other good CSS architectures worth considering as well, like SMACSS and Atomic. And rolling your own is fine too.

Collapse
davedodea profile image
Dave O'Dea Author

Great, thank you Isaac.

Collapse