9 min read

Dealing with class names and their associated styles across large projects and teams has always been a challenge. The Cascade, something that we’ve been taught to rely on, often comes back to bite us. Unexpected styling collisions forces us down a specificity rabbit hole as we get more and more specific when we create new elements or move them around. This is where object-oriented CSS syntaxes like BEM come to the rescue. BEM provides valuable structure to your CSS while also providing advantages to code modularity and maintainability. By creating contained components with low specificity, we can free ourselves from these issues. By using BEM in your code, you will create a modular code-base that can be reused anywhere in your project, and by anyone on your team. This post will get you up and running with BEM and show you how SASS can make BEM even easier to implement.

What Is BEM

BEM is a methodology originally developed by Yandex, as a better way of structuring web applications with a particular focus on reusability across large projects and teams. It stands for Block, Element, Modifier, which are the three components that make up a BEM object. The idea is that describing your UI elements in this way tells you everything you need to know about it, while consolidating all its styles down to a single class name. Blocks describes where on the page a module goes. Elements describes the individual component itself. Modifiers gives us the state of the element, whether that be a visual modifier or a functionality one. Through these class names, BEM gives us a clear connection between our markup and our styles.

Why BEM

One of the major problems BEM is solving is the clear identification of components so that they may be reused throughout your project. It accomplishes this by using a clear naming convention that gives a developer complete context of the components use. BEM unchains your component’s styling from the DOM it is surrounded by, enabling your team to create new and existing elements without fear of that component needing some unrelated DOM element in order to receive proper styling.

If used properly, BEM will greatly reduce the specificity battle usually associated with implementing new elements or reusing components in multiple parts of your application. BEM classes describe a component’s context and state, so you will know when to use a component or when a new element is necessary. Plus, now thanks to improvements in SASS, you can do this without writing any more code than you currently are.

Blocks

A block is the first part of our selector naming convention. It describes the highest level of abstraction, or in simpler terms, a page component. Imagine we are building a simple web app that finds and plays podcasts, our main view would likely be made up of several of these components including a playlist, search box for finding shows, and an audio player with controls. Each of these would be considered a block in BEM. When naming these blocks, they should be representative of that component’s role on the page and consist of a single word or multiple words separated by a single hyphen.

.podcast-playlist {}
.podcast-search {}
.podcast-player {}

Each one of these clearly denotes the component it will be attached to. By looking at our selectors, we can easily decipher the role of each component. Notice that we prepended each one with podcast, which seems redundant at first. However, if you think about how our application might grow, if we were to add more search options such as artists, genre, etc. we might want to style those differently. When in doubt, be as descriptive as possible.

Elements

The next level of abstraction is the element. These are the major parts that make up each block and are always children of that particular block. Taking our podcast app example again, our audio player would have a play button as well as forward and back controls. When naming an element we start out with its parent block’s name, followed by double __, and then the element’s name. Just like with blocks, our element names should be descriptive of what the element’s role actually is:

.player-controls__play-button {}
.player-controls__back-button {}
.player-controls__next-button {}

Notice that the parent/child relationship is represented by the class name itself, and its status as a nested selector as you probably are used to in your CSS. This is what makes BEM so useful, we aren’t creating deep specificity just to describe a relationship between a parent and a child selector.

Modifier

The last layer of abstraction is the modifier. This refers to a state or variation of an element. In our example, our play button probably has a playing and a paused state. It also could have a dark and a light variation. Either situation requires a modifier, which describes a variation of a particular element. Modifiers are represented by adding a double — after a block and an element followed by the name of the modifier:

.player-controls__play-button--playing {}
.player-controls__play-button--paused {}

Once again, we have a very clear description of the element, its context, and now its variation (in this case play state), all from just a class name.

Better BEM With SASS

In 3.3, SASS introduced functionality that made writing BEM syntax a breeze, taking away one of the few annoyances of BEM. Let’s take a look at our player controls in SASS:

.player-controls {
&__play-button {
   &--playing {
   }
   &--paused {
   }
}
}

That code compiles into exactly what we need:

.player-controls {}
.player-controls__play-button {}
.player-controls__play-button--playing {}
.player-controls__play-button--paused {}

We are able to build our class names using SASS’s & shorthand and nesting capabilities. This means it actually takes the same amount of code to write our new names as it did to create the same context using nested selectors. The great thing is in areas where we need normal nesting, we can do that as well:

.player-controls {
&__play-button {
   &--playing {
     span {
     }
   }
}
}

Another area where SASS can help is with shared styles. It is important that we keep our code DRY so we don’t want to repeat code for each one of our elements that use a shared set of styles. At first blush, this may seem like a problem with BEM since we are using single class names. While some advocate for multiple class names as a solution, I believe SASS provides us with a cleaner solution.

SASS placeholders are a great way to keep our code DRY while sticking to BEMS methodology of providing contextual awareness to our styles. In our podcast app, we can imagine that the three control buttons we created above would share a lot of the same styles. Here is how we would handle that with SASS:

%player-controls__button {}
.player-controls__play-button {
@extend %player-controls__button;
// additional styles
}
.player-controls__back-button {
@extend %player-controls__button;
// additional styles
}
.player-controls__next-button {
@extend %player-controls__button;
// additional styles
}

Notice we still use BEM naming conventions when naming our placeholder, making sure we have context for the shared styles as well. I prefer this approach as it keeps the DOM clean of unnecessary classes that only partially describe the element, while still ensuring we can leverage shared styles with minimal effort. Context is also kept not only in the DOM as with the multiple class approach, but in your stylesheet as the shared style is directly referenced using extend. It’s truly the best of both worlds.

To BEM or Not To BEM

BEM is not an exact science, nor should it be used for every element on your page. When deciding if an element is part of a block you need to ask yourself “Is this element an integral part of this component?” For example, you may have a logo that happens to be part of a sidebar component, but does the styling of that logo rely on the sidebar for context? In most cases, the answer is probably no, and you would want to just call that .logo.

Another case is what I refer to as helper classes, or classes that are used for presentation elements throughout your app. Classes that show and hide elements or elements of a grid layout are two examples. These are also context agnostic and don’t need to be BEM-ified.

Nesting

Nesting is another area where BEM gives you flexibility. A general rule of thumb is that an element should only rely upon the context of a single parent block, even if that block is part of another block. Simply, if the context of an element relies on another element, represent that in the name of the element itself as opposed to nesting it. This is how that situation, might look in our podcast app:

Instead of nesting our name and description elements as a child of search-results__item, we simply make them parallel elements with search-results__item as part of their name. This still provides context for these elements without creating overly verbose naming.

In some cases though, you might not be able to avoid nesting, especially when your component layouts get complicated. Remember, we still want to preserve context, so while nesting can be verbose, it can be necessary in order to accurately describe a component:

We handled the above example using nesting. Our search view (our block) is split into two major elements (show-search__search-box & show-search__results) with their child elements nested inside of them. You can really handle this situation either way, you choose where to draw the line where nesting makes sense.

Luckily if you decide nesting is necessary SASS can also handle this easily:

.show-search {
&__search-field {
}
&__search-button {
}
&__search-results {
   &__item {
   }
   &__item-name {
   }
   &__item-description {
   }
}
}

Conclusion

BEM offers a great way to improve the contextual awareness of your code base. By having all the styles for a particular UI element contained in a single class, you know exactly what is required to modify or create a new instance of that element. You also get the full context for your styles from the CSS file alone. The flexibility BEM provides allows you and your team to truly make the syntax yours. Your styles will be more readable, more transparent, and more reusable. Plus with SASS, writing BEM has never been easier. If you work on a large team and/or project, you owe it to yourself to give BEM a deeper look.

About The Author

Brian is a Front-End Architect, Designer, and Product Manager at Piqora. By day, he is working to prove that the days of bad Enterprise User Experiences are a thing of the past. By night, he obsesses about ways to bring designers and developers together using technology. He blogs about his early stage startup experience at lostinpixelation.com, or you can read his general musings on twitter @b_hough.


Subscribe to the weekly Packt Hub newsletter. We'll send you the results of our AI Now Survey, featuring data and insights from across the tech landscape.

LEAVE A REPLY

Please enter your comment!
Please enter your name here