Why your CSS needs BEM
Sep 6, 2017 • Jed Lehmann
Everyone writes CSS differently. This different approach would be fine if we all worked alone, but a team environment needs consistency and predictability.
I used to try and keep CSS classes to a minimum, with perhaps a parent class on a block of markup, for example a class of "alert" for an alert message, then use CSS selectors to target the HTML elements within that component.
This becomes a problem when HTML changes over time – if you change a HTML tag within that "alert" component that doesn't have its own class, the styles are no longer applied to that element and there's no indication of what might happen. The HTML looks pretty, but what a nightmare to maintain!
Using more classes help us understand the relationship between the HTML and CSS.
But what happens to our nice, lean HTML? Well, put simply, it adds some weight. And a bit of meat on the bone really helps in this case. No longer are we afraid of unforseen side effects when making a change in the HTML.
But the next question quickly arises. If we are using more classes, how do we name them consistently so the whole team knows how to author and understand the markup?
We need a naming system for that.
What naming systems are available?
Several naming and organisational systems have been created by people wanting to manage their CSS. What you choose to use probably doesn't matter as much as having a system in place, and making sure the team sticks to it.
What system did we choose?
We decided on BEM and haven't looked back since.
- It has momentum. People are using it, and talking about it.
- It is easy to explain, author and maintain.
- It isn't as dogmatic as some of the other options – there is room for interpretation in how to write and structure your CSS.
What is BEM?
BEM stands for block, element, modifier. It was created by Yandex for "developing websites that need to be created quickly and maintained over many years".
- A block represents an element in your app. For example the alert pictured below.
- An element is an object within that block. For example the alert's title.
- A modifier is used to create variations of a block (or it's elements). For example a danger alert.
Perhaps the creation of BEM was influenced by the Law of Demeter, which is a rule from object-oriented software development that determines that methods should be coupled and self-contained so they are reusable and aren't affected by other methods. BEM is based on this principle, and its component approach it perhaps it's most useful aspect.
BEM also has guidelines for how to organise your CSS (or SCSS or Less) directory, but many people choose to ignore that and just use the BEM naming convention. With regard to how we organise our SCSS directory, well, that's an article for another day.
What do we love about BEM?
- You can use it for any project, not just large ones. Even small projects benefit from having this structure.
- You don't need to nest selectors as deep in your styles. This reduces issues surrounding specificity.
- Blocks are reusable, so it's easy to move them to another part of the page or application.
- You can scan over HTML and instantly understand the relationships between elements, and the relationship to the CSS.
Some problems we have encountered when using BEM
1. Taming grandchild selectors
Sometimes a block has elements which have their own children. How do we handle these? One way is to write it just as it's structured, so something like this
.alert__title__label. This can get out of hand though, so our preference is to treat each element as if it's a direct child of the block, so you would write
.alert__title-label. This also makes it easier to move HTML around within the component.
2. Wrappers outside of the block
Some blocks need a parent wrapping element for styling which is still a required component of the block. It feels slightly wrong to call it something like
.alert__wrapper and have it placed outside the
.alert block itself, but sometimes this is the solution we go for, as I haven't heard of a better solution. In most cases you can use utility or grid classes to give us what we need, so instances of this happening aren't overly common.
3. Having to add classes to everything
BEM dictates that you should add classes to every element in a component. However, sometimes we break the rules if the elements are commonly used across the application, such as paragraph tags. Adding classes to these elements adds weight to the HTML despite the class not being used for anything in the CSS. Our rule of thumb is that anything that needs CSS rules applied to it should have a class, otherwise you can omit the class.
We have been using BEM for over two years now, and have found that any problems are greatly outweighed by the benefits it gives us. We can now think in components and systems rather than pages, and we have more confidence in our markup and styles.