What is BEM Methodology?
When you are building smaller websites, how you organize your styles is usually not a big problem. You create your usual files, write all the needed CSS, and that’s all. However, when it comes to larger, more complex projects, how you organize your code becomes crucial. How the code is structured is even more important if you are working in a team consisting of multiple front-end and back-end developers.
Today, there are plenty of methodologies with the aim of reducing CSS code and making your CSS code more maintainable. In this article, I am going to explain and provide a few examples of one of them: BEM.
BEM stands for Block Element Modifier. The main idea behind it is to speed up the development process, and ease the teamwork of developers by arranging CSS classes into independent modules. If you ever saw a class name like
BEM stands for Block Element Modifier. The main idea behind it is to speed up the development process, and ease the teamwork of developers by arranging CSS classes into independent modules. If you ever saw a class name like
header__form--search
, that is BEM in action. Yes, classes can be named very long, but they are all readable and understandable.
Note that the best practice is to use BEM only with classes, and not IDs because classes allow you to repeat names if necessary and create more consistent coding structure. Also, if you want to break your website into organized modules, it should consist of the same structure: block, element, and modifier. Where each block can have multiple elements, and both block and elements can have multiple modifiers. However, let’s first start with the basic BEM structure and explain it with examples.
Block
A block represents an object in your website. Think of it as bigger structural chunks of your code. Most common blocks on every website today are header, content, sidebar, footer, and search. Blocks in BEM are always a starting point of chaining your CSS classes on to. Take a look at a few block examples:
- a content
- a menu
- a search form
.content {/* Styles */}
.menu {/* Styles */}
.search {/* Styles */}
Element
An element is a component within the block that performs a particular function. It should only make sense in the context of its block:
- a content article
- a menu item
- a search input field
.content__article {/* Styles */}
.menu__item {/* Styles */}
.search__input {/* Styles */}
Modifier
A modifier is how we represent the variations of a block. If you’ve ever used Bootstrap, then the best example would be the button sizes. Button sizes are just size variations of the button itself, which makes it the modifier:
- a content featured article
- a menu link
- a search field with or without icon
.content__article--featured {/* Styles */}
.menu__item--link {/* Styles */}
.search__input--icon {/* Styles */}
Naming Conventions
The primary purpose of BEM methodology is to make names of CSS selectors as informative and transparent as possible. Original BEM style is defined in this way:
Block name is usually a single word like
.header
, but if you have longer block definition then it is divided with a single hyphen -
:.lang-switcher {/* Styles */}
Element name starts with double underscore
__
:.lang-switcher__flag {/* Styles */}
Modifier name starts with single underscore
_
:.lang-switcher__flag_basic {/* Styles */}
There is only one very critical rule in BEM methodology - a modifier cannot be used outside of the context of its owner.
Example:
.btn_big {/* Styles */}
You can use
btn_big
only if header is defined also.
Bad example:
<div class=”btn_big”>...</div>
Good example:
<div class=”btn btn_big”>...</div>
Beside these original BEM styles, there are alternative naming schemes like Harry Roberts and CamelCase styles.
Harry Roberts style example:
.block-name__element-name--modifier-name {/* Styles */}
CamelCase style example:
.BlockName__ElementName_ModifierName {/* Styles */}
There are few others too, but these two are the most common ones. Personally, I am a fan of the naming convention proposed by Harris Roberts, which has the following rules:
- Names are written in lowercase
- Words within the names of BEM entities are separated by a hyphen
-
- An element name is separated from a block name by a double underscore
__
- Boolean modifiers are delimited by double hyphens
--
- Key-value type modifiers are not used
The reason why this naming convention is much better formed than others is that you can easily distinguish modifier element from others. In original naming conventions, modifier would be defined like this:
.block__element_modifier {/* Styles */}
But as you can see, there is not very much difference between a single and double underscore. On the other hand, double hyphen provides clean separation, and you can see the modifier instantly:
.block__element--modifier {/* Styles */}
BEM Example in Different Formats
Please note that besides CSS, BEM is also very useful in organizing your JSON, XML, tree files, or any format supports nesting. Think of BEM methodology as a good way to build your UI.
Let’s consider the following HTML, structured in BEM format:
<header class=”header”>
<img class=”header__logo”>
<form class=”header__search-from”>
<input class=”header__search-from__input” type=”input”>
<button class=”header__search-from__button” type=”button”>
</form>
<div class=”header__lang-switcher”></div>
</header>
The same can be achieved using JSON and XML format.
XML:
<block:header>
<block:logo/>
<block:search-from>
<block:input/>
<block:button/>
</block>
<block:lang-switcher/>
</block>
JSON:
{
block: ‘header’,
content: [
{ block: ‘logo’ },
{
block: ‘search-form’,
content: [
{ block: ‘input’ },
{ block: ‘button’ }
]
},
{ block: ‘lang-switcher’ }
]
}
File System Organization of a BEM Project
In BEM, it is critical to organize your files in a correct manner. Not only is BEM providing you a great organization of CSS classes and making them completely understandable, but also gives you a very maintainable file structure. Let’s take an example project, using BEM file organization technique with SASS files:
blocks/
input/
__box/
--big/
input__box--big.scss
input__box.scss
button/
--big/
button--big.scss
As you can see above, just by seeing the subfolder structure inside your main folder, everything is clear and organized. In this way, it makes no difference who is working after you or if you are working after someone, because it is incredibly easy to follow the same pattern.
Dividing BEM Project into Platforms
Besides just organizing your files using BEM methodology techniques, you can also go into more specific things. For example, if you are building a web project which is going to be fully responsive, and the client specified that some blocks on the mobile are totally different than on desktop devices, it would be best to divide your BEM folder structure into platforms. Example of organizing buttons on various platforms:
common.blocks/
button/
button.scss
desktop.blocks/
button/
buttons.scss
mobile.blocks/
button/
button.scss
Note that this is just an example if you want to organize your whole project using BEM methodology. File tree with BEM structure is not mandatory to use BEM correctly, you can use BEM just in some segments of the project. So far I haven’t been using this strict BEM file structure organization where every element and modifier has its file created. Instead, I am just creating a file structure for blocks which are having a declaration of its elements and modifiers.
BEM in Practice
Since you are now familiar with naming conventions, I will demonstrate BEM methodology in practice. Let’s say that we have this HTML code in action:
<a class=”btn btn--big btn--primary-color” href=”#” title=”Title”>
<span class=”btn__price”>$3.99</span>
<span class=”btn__text”>Product</span>
</a>
With the following CSS markup applied:
.btn__price {/* Styles */}
.btn__text {/* Styles */}
.btn--big {/* Styles */}
.btn--primary-color {/* Styles */}
Now, don’t be mislead. In our examples so far we almost always had a block, element, and modifier, which doesn’t always have to be the case.
For example, let’s say we have a block named person. A person has legs and hands, it can also be female or male. If we want to define a male person with a right hand it will look like this:
.person--male__hand--right {/* Styles */}
Now you can see the real meaning of the BEM. We defined a person which modifier is a gender. Since it doesn’t matter if a person is male or female, it has a hand, and hand is an element. And again, each person can have right or left hand which is again a modifier.
In another case, if we want to define general person with a single hand, we will do it like this:
.person__hand {/* Styles */}
As you can notice, once you get comfortable with BEM it’s very easy to structure your CSS and HTML structure with it.
Using BEM with CSS Preprocessors
Personally, I can not imagine starting any new project without using one of the CSS preprocessors. As you all know, preprocessors are a great thing and they are providing us a lot of benefits, and most importantly they are a perfect match with BEM methodology.
In the following example, you can see the most typical example of BEM, in combination with SASS:
.person {
&__hand {/* Styles */}
&__leg {/* Styles */}
&--male {
/* Styles */
&__hand {
/* Styles */
&--left {/* Styles */}
&--right {/* Styles */}
}
&__leg {
/* Styles */
&--left {/* Styles */}
&--right {/* Styles */}
}
}
&--female {
/* Styles */
&__hand {
/* Styles */
&--left {/* Styles */}
&--right {/* Styles */}
}
&__leg {
/* Styles */
&--left {/* Styles */}
&--right {/* Styles */}
}
}
}
SASS code will compile into the following CSS:
.person__hand {/* Styles */}
.person__leg {/* Styles */}
.person--male {/* Styles */}
.person--male__hand {/* Styles */}
.person--male__hand--left {/* Styles */}
.person--male__hand--right {/* Styles */}
.person--male__leg {/* Styles */}
.person--male__leg--left {/* Styles */}
.person--male__leg--right {/* Styles */}
.person--female {/* Styles */}
.person--female__hand {/* Styles */}
.person--female__hand--left {/* Styles */}
.person--female__hand--right {/* Styles */}
.person--female__leg {/* Styles */}
.person--female__leg--left {/* Styles */}
.person--female__leg--right {/* Styles */}
If you want to go even further, you can use a handy SASS mixins for BEM:
/// Block Element
/// @param {String} $element - Element's name
@mixin element($element) {
&__#{$element} {
@content;
}
}
/// Block Modifier
/// @param {String} $modifier - Modifier's name
@mixin modifier($modifier) {
&--#{$modifier} {
@content;
}
}
And you can use it like this:
.person {
@include element('hand') {/* Person hand */}
@include element('leg') {/* Person leg */}
@include modifier('male') {
/* Person male */
@include element('hand') {
/* Person male hand */
@include modifier('left') {
/* Person male left hand */
}
@include modifier('right') {
/* Person male right hand */
}
}
}
}
Which will produce the following CSS output:
.person__hand {
/* Person hand */
}
.person__leg {
/* Person leg */
}
.person--male {
/* Person male */
}
.person--male__hand {
/* Person male hand */
}
.person--male__hand--left {
/* Person male left hand */
}
.person--male__hand--right {
/* Person male right hand */
}
I know that most likely you won’t have a use case this long, but this is a great example of how BEM is used and why it’s so powerful, both in small and large scale projects.
Starting Your BEM Project
As explained in the official BEM documentation, the easiest way to start you own new BEM project is to use existing GIT repository. Simply use Git clone command:
$ git clone https://github.com/bem/project-stub.git
Next, go to a newly created directory and install all dependencies:
$ npm install
All required dependencies will be installed:
Build the project using ENB:
$ node_modules/.bin/enb make
Run a server mode for development:
$ node_modules/.bin/enb server
As a result, the following message appears:
Server started at 0.0.0.0:8080
Now, this means that the server is up and running. You can now check the results on this address:
http://localhost:8080/desktop.bundles/index/index.html
As you can see, there are a lot of elements already created which are defined inside
bemjson
file which is located here:project-stub/desktop.bundles/index/index.bemjson.js
You can see and explore the current structure of the file that is generating all that HTML, which you see at your localhost
index.html
file. We are going to alter this file to get our “Person” BEM project which we explained in a previous chapter. You can remove (or comment) the whole code from index.bemjson.js
file, and replace it with this one:module.exports = {
block: 'page',
title: 'Person BEM',
favicon : '/favicon.ico',
head : [
{ elem : 'meta', attrs : { name : 'description', content : '' } },
{ elem : 'meta', attrs : { name : 'viewport', content : 'width=device-width, initial-scale=1' } },
{ elem : 'css', url : 'index.min.css' }
],
scripts: [{ elem : 'js', url : 'index.min.js' }],
content: [
{
block: 'person',
content: [
{
elem: 'male',
content: [
{
elem: 'leg',
mods: {side: 'left'},
content: 'Male person leg -- left'
},
{
elem: 'leg',
mods: {side: 'right'},
content: 'Male person leg -- right'
},
{
elem: 'hand',
mods: {side: 'left'},
content: 'Male person hand -- left'
},
{
elem: 'hand',
mods: {side: 'right'},
content: 'Male person hand -- right'
}
]
},
{
elem: 'female',
content: [
{
elem: 'leg',
mods: {side: 'left'},
content: 'Female person leg -- left'
},
{
elem: 'leg',
mods: {side: 'right'},
content: 'Female person leg -- right'
},
{
elem: 'hand',
mods: {side: 'left'},
content: 'Female person hand -- left'
},
{
elem: 'hand',
mods: {side: 'right'},
content: 'Female person hand -- right'
}
]
},
]
}
]
};
Now, the following HTML will be generated:
<div class="person">
<div class="person__male">
<div class="person__leg person__leg_side_left">
Male person leg -- left
</div>
<div class="person__leg person__leg_side_right">
Male person leg -- right
</div>
<div class="person__hand person__hand_side_left">
Male person hand -- left
</div>
<div class="person__hand person__hand_side_right">
Male person hand -- right
</div>
</div>
<div class="person__female">
<div class="person__leg person__leg_side_left">
Female person leg -- left
</div>
<div class="person__leg person__leg_side_right">
Female person leg -- right
</div>
<div class="person__hand person__hand_side_left">
Female person hand -- left
</div>
<div class="person__hand person__hand_side_right">
Female person hand -- right
</div>
</div>
</div>
As you can see from the code above, the default BEM coding scheme was used in this scenario since we are just using default settings which BEM provided to us. There are a lot more commands and options which you can explore and use, such as creating new pages, blocks, or modifying BEM HTML. I will not go too deep into this, and it can all be found in the official BEM documentation.
Advantages and Concerns
Advantages
- BEM is excellent for maintaining. How many times have you had to work after someone on a large scaled project and you are just too afraid to change anything without something unknown collapsing? When using BEM, you know the exact purpose of the element and in which block it may appear.
- Class names are logical and intuitive, and every member of the team knows what that element does on the website. BEM gives everyone on a project a declarative syntax they can share so they’re on the same page.
- BEM eliminates nested CSS selectors. Every single HTML element has its own CSS class, and by its name you know what its purpose is. One selector to rule them all.
Concerns and Common Mistakes
- Do not go too deep into nesting. The main rule should be not to use more than two levels of parent and child.
- Be careful with where you start your block scope. A common mistake here is when a developer is using block, but he is not realising that at the later point of development that same block will have main parent block which will possibly break the rule with nesting.
- Avoid SASS @extend. To quote Harry Roberts on this:
You can create a greater number of combinations in the view by not ‘tying’ classes together in Sass. The HTML has a much better paper trail in that you can see every class acting on a piece of the DOM. Your CSS stays much slimmer in that you don’t have to create new placeholder classes (or the manifest classes that combine them) every time you want to create a new piece of UI.
Conclusion
When I saw BEM coding scheme for the first time, my first thought was:
These classes are just too long to write and read.
But after giving it a try, now I can not imagine starting a new project without using it. For me, BEM massively improved my code maintainability, and I can for sure say that every developer who is going to be “thrown” into the BEM-based project will catch up really quickly with the whole code structure.
Despite all this, there’s a lot of discussion on social networks about BEM. Some say BEM isn’t good, wondering why they should write such long name classes instead of just use default HTML nested elements. Well, no one says that you must like BEM, but the fact is that the majority of front-end developers embrace it and find it extraordinary useful.
No comments: