There has been a lot of back-and-forth lately at thoughtbot about how to best structure our CSS class names. Inevitably, we always wind up discussing BEM with mixed opinions. Having completed a smaller greenfield project recently that used BEM naming, I can safely say I’m a convert. The organizational approach of the framework provides a great guideline on how to manage the same content that needs to be viewed in different contexts. Combined with a preprocessor, BEM makes keeping your CSS modular and object-oriented a breeze. If you’re working on a project that follows the MVC pattern, BEM fits right at home. Don’t let its syntax scare you away!
What is BEM?
To give a quick recap, BEM stands for “Block”, “Element” and “Modifier”, and is a class naming convention. Each block could be an object group or feature (for example, a search form), the elements would be its children (a search input and button), and a modifier could be one of its states (such as “disabled”, “is animating”, or “is visible”).
.search { // Block
align-content: center;
display: flex;
&--is-disabled { // A Modifier for disabled state
display: none;
}
}
.search__input { // Block with an Element
border: 1px #000 solid;
display: inline-block;
flex: 1;
padding: 1.5em 1em;
}
.search__button { // Block with another Element
background-color: #000;
color: #FFF;
display: inline-block;
font-size: 1.25em;
}
How can it help modularity?
Now that our class names are dependent on the blocks, we can create stylesheets
based on them, and, with Sass, nest any contextual
modifiers underneath. Using our example above, all of our styles for the search
feature could be held in a singular search.scss
file. I used to have the bad
habit of structuring my stylesheets based around views and layout. If I wanted
the landing page’s search to be more prominent than the one in the header, I may
have manipulated the .search { ... }
selector within my landing.scss
and
header.scss
files. Clearly that is not ideal or maintainable if more instances
of the search form exist. Instead, we can use Sass’ parent selectors write
something like:
// Filename: search.scss
.search {
align-content: center;
display: flex;
&--is-disabled {
display: none;
}
}
.search__input {
border: 1px #000 solid;
display: inline-block;
flex: 1;
padding: 1.5em 1em;
// Landing page specific styles
.landing & {
padding: 2.5em 2em;
}
}
.search__button {
background-color: #000;
color: #FFF;
display: inline-block;
font-size: 1.25em;
// Landing page specific styles
.landing & {
font-size: 1.5em;
}
}
This way, if any blocks or their elements needed to be changed for certain pages, you know to go straight into the dedicated stylesheet for that feature, rather than needing to backtrack and remember which layout sheet held what styles.
How does it match with MVC?
From a front-end development point of view, I found the rationale behind MVC and
BEM to be similar. This means that when working on, say, a Rails project, I
could keep the same mindset for writing both markup and styles. In the MVC
pattern, models dictate how the app and data is structured, and each model
describes a set of data. In BEM, blocks—like navigations and
forms—make up the interface for the app. Each block can describe one UI
object (e.g our search form) or a set of data too (e.g. a .user
with a
.user__name
and .user__birthday
), and there can be multiple copies of it on
the DOM. With views, it is possible to display a model’s data in varied ways
without changing the information itself. Similarly, using modifier classes and
parent selectors, you can tweak the visual treatments for many instances of one
block.
What if I don’t like the syntax?
In all our discussions about BEM, the fact that it uses underscores and dashes
in its naming system always get brought up. Some team members find them too
distracting to adopt BEM in their workflow. However, I firmly believe that
there’s no reason for the dogma and it’s not the specific use of __
and --
that makes BEM, BEM. If you prefer to use single dashes or other ways of
seperating your B’s, E’s and M’s, the methodogy is more than flexible to
accommodate your preferences. While the specific syntax may not be for everyone,
BEM is undoubtedly an effective way to organize your front-end. Even if you
don’t like the syntax, I’d encourage you to try BEM out anyway and tweak it to
your liking.
Additional notes
Read the documentation over on BEM’s official page.
Using Hound?
Are you using Hound for SCSS linting? By default, it does not support BEM syntax. However, if you’re interested in having it work, add the following to its corresponding files:
In hound.yml
scss:
config_file: config/scss.yml
In config/scss.yml
SelectorFormat:
enabled: true
convention: BEM