Hi, some time ago jQuery team asked us about BEM, and we cleared a lot of points for them. Answers are quite useful, so we decided to publish them free.
1. How easily is BEM kept maintainable long term?
Easy maintenance is what BEM was invented for.
Actually all the issues with CSS maintenance are because of cascade and strong coupling of components. And BEM is all about independence of blocks and reducing cascade to minimum level.
We have a lot of real experience with BEM on our portal and it proved to be a great solution.
Example 1.
ul a {
position: absolute;
}
won't work as soon as you'll get second level of nesting for lists.
Example 2.
Considering menu can't have any other list items:
ul.menu li {
...
}
and then some components with own dropdown with own menu appear in list item.
Well, BEM does not restrict usage of btn
instead of button
;)
You can consider any naming strategy you want.
E.g.: context
or ctx
or c
, attributes
or attrs
or as
.
The choose is yours — BEM doesn't srink you.
There is still some "problem" with elements and modifiers, i.e. btn__txt
and btn_hvrd
, but we strongly believe that there's no real problem in typing. And of course there's no problem with kilobytes due to gzip. But what is really important for huge rapid projects which live for a long time is code readability and self-descriptive names of components is just a must.
Not so cool for common block library with a huge amount of users.
That was something odd when we invented BEM. But right now that's a common idea:
OOCSS, Atomic CSS, etc. and web components standard try to hide internal world of a block from other ones. Web components use shadow DOM, BEM uses namespacing to achieve the same result but without necessity to wait for support from browsers or any additional JS.
Historical reason of having namespaces for modifiers is that joined selectors like .a.b were not supported in old browsers. Not it's not a restriction but in BEM there's also a concept of mixes — possibility to have a few different entities on the same DOM node. And namespaces help to distinguish modifier of which block is it.
Without mixes it's possible to have .btn._hvrd
but we are sure that mixes are useful thing.
But what is often left in shadow is possibility to mix different entities on the same DOM node. E.g. it's possible to have <input class="input form__login">
which means we've got an input
block (can be reused somewhere else) and login
element of form
block at the same time. So everything about abstract input
will be provided by .input
selector and things like margins, etc — with .form__login
.
4. Neutering the Cascading potential of CSS code by making everything overly specific.
Yes, that looks strange at the first sight but soon you'll find it very convenient.
Cascade is cool for fast write-and-throw-away approach. But when we need bullet proof reusable components it just doesn't work.
Cascade creates strong coupling and results in impossibility to reuse such code.
5. The arbitrary distinction between blocks and elements.
Let's look at JS (actually OOP) analogy. JS class point [x, y] is just a field of Figure class or one more class Point.
If it has a lot of methods it's most likely a class by its own. Otherwise field is enough.
The same is for blocks and elements. It's always for your consideration.
With practice that's easier than it looks. When an entity is impossible without its parent — that's an element. When you find yourself trying to reuse an element somewhere in a project without its parent and inner complexity of element became bigger — that's a standalone block.
But what is often left in shadow is possibility to mix different entities on the same DOM node. E.g. it's possible to have <input class="input form__login">
which means we've got an input
block (can be reused somewhere else) and login
element of form
block at the same time. So everything about abstract input
will be provided by .input selector and things like margins, etc — with .form__login
.