If you are reading this article, you probably know what B.E.M (Block - Element - Modifier) is. For those who don’t hop on over to CSS-Tricks to get the quick run down, it’s okay I’ll wait. For the others, let's get straight to business.
The front-end world is in no shortage of frameworks, libraries or methodologies. Why on earth am I contributing another one? Well, we all know nothing is perfect, and there is always something that works better for specific scenarios. With that said I’m not claiming that this new approach is the end all and be all of the CSS methodologies. I liked BEM which was why I decided to put my spin on it.
The similarities are that you still build your components with a block, element, and modifier in mind. The naming convention, however, is very different and far more condensed. Things can quickly get long with traditional BEM names. Let's take this example of a standard button:
<pre><code>
<a href="#" class="checkout-button checkout-button--active">
<span class="checkout-button__label">Checkout</span>
<span class="checkout-button__icon"></span>
</a>
</code></pre>
At best this is merely okay, but it gets worse when you start adding more modifiers or on more complex components. Not to mention the JS, but we will get to that in a moment. Here’s what that same component will look like with BEMM:
<pre><code>
<a href="#" class="b-checkout-btn m-active">
<span class="e-label">Checkout</span>
<span class="e-icon"></span>
</a>
</code></pre>
Much easier to read right? Granted this is a simple example, so the traditional BEM markup is perfectly acceptable, but in the words of Nicolas:
Projects become increasingly more complex as time goes by and if the markup is not apparent at first glance it can become harder and more time consuming to maintain a project.
BEMM uses a naming convention where the tags are described by prefixing class names with these identifiers: .b- , .e-, .m- and .g-.
Components are broken down into blocks to group code and visual elements together. These elements are given a unique name and prefixed by "b-" to represent a block element. This makes the HTML much more legible without knowing much about the CSS itself.
An example of a block element is usually the component as a whole, e.g., dropdowns, buttons, tabs, media objects etc. Block elements can be nested inside other block elements, but as a rule, block elements are considered a block element when they can live by themselves.
Elements are contained within component blocks, usually as the first child descendant but not restricted to and prefixed by "e-". These elements are what makes up a block component, for example in a dropdown this would be the list items inside the drop down.
The styling of elements is dependent on the parent block element; in other words, they are nested in CSS. This allows reusing the element names without affecting the CSS globally or having to use unique and lengthy class names. Elements should never live on a root level without being wrapped by a block element.
In edge cases where a block element nested inside another block element have conflicting names, consider a different name, or look at something like a CSS Modules for more technical implementation.
Modifiers are applied at any level of the component, and they can live on block or element tags. These can also be seen as local helper classes. In the stylesheet these are generally nested at the level they are needed to avoid having to use unique class names. This allows you to use a class name like “m-active” on multiple elements without having to have unique names.
Modifiers can be anything from subtle style changes like background colours or font sizes to layout floating or entire component theme colours.
The only differences between regular modifiers and global modifiers are the prefix and the fact that global modifiers have to be generic enough to be used on any component without requiring unique style overwrites. Global modifiers are also not dependent on a block or element tag and can be used independently.
All custom styling class names should have the required prefix ".b-, .e-, .m-, .g-", and longer class names are separated by dashes. ".b-promo-header" - Names can be abbreviated to shorten the name as long as it's legible or clear what it means. It needs to be at least obvious to someone not familiar with the project. Something like “button” can be shortened to “btn”.
Most of the time JavaScript is used to do simple modifications to the markup to show/hide or change the visual state of a component. The easiest way to accomplish this is by adding and removing CSS classes to the component. My biggest issue with this has always been the use of style specific classes inside the JS code. As soon as you refactor a component, you risk changing a class name referenced somewhere in JS and eventually break site functionality. Even something as simple as renaming a block component can cause this.
If you were using something like CSS Modules, you probably wouldn’t have that much of an issue here. For most of us, however, and especially to those front-end devs who never touch JS code, this is an issue.
BEMM deals with this by only allowing modifier classes to be used in JS. Keeping it simple by using class names such as “m-active” can mean multiple things depending on the component it’s applied to, yet still, make it easy to understand when glancing over the code. A dropdown can be “m-active” when it’s open, or a modal can be “m-active” when visible on the screen. Renaming a component, in this case, would not break any functionality.
When traversing the DOM, you need an identifying class name or id for the JS code to know where to apply its updates. With BEMM you use a prefix we haven’t mentioned so far. This prefix is strictly meant to find DOM elements with JS. These are prefixed with “.js-” or “.j-” if you want.
With this approach, you make a clear separation between classes for styling and classes for JS. This avoids components breaking when refactoring old code as it’s evident that the class name on an element is connected to some JS code. This is not so much an issue with more modern JS frameworks like React and Angular where the component logic knows what the markup looks like.
To wrap things up, BEM itself is not bad, and there is nothing wrong with using BEM. I found that this approach simplified the use of the BEM naming convention which in turn made reading markup easier. As I said before, BEMM is by no means a perfect solution. So give it a try, and see if it works for you. Alternatively, even better yet, provide your spin on it and let us know if you managed to improve it.