Whether you’ve just discovered BEM or are an old hand (in Web terms anyway!) and have been using it for the past few years, you can probably already appreciate what a useful methodology it is.
If you don’t know what BEM is I suggest you read about it here before continuing with the post.
Now, I’m under no illusion that this is a beautiful way of naming things. It’s absolutely not. One of things that put me off adopting it for such a long time was how eye-gougingly ugly the syntax is. The designer in me didn’t want my sexy markup cluttered with dirty double underscores and foul double hyphens.
The developer in me looked at it pragmatically and eventually the logical, modular way of building UI outweighed the right-side of my brain complaining “but it’s not pretty enough”.
I certainly don’t recommend picking living room centre-piece this way, but when you need a life jacket (as you do in a sea of CSS) I’d take function over form any day.
Anyway – onto the dilemmas:
These bad boys are the bane of my life — and I’m sure their misuse is one of the reasons people have an immediate aversion to BEM. I’ll give you an example:
As you can imagine, this can quickly get out of hand and the more nested your component is, the more hideous and unreadable the classnames become. I’ve used short words like card, body, text and link but you can imagine how out of control it becomes when your block element is called something like drop-down-menu.
My belief is the double underscore pattern should only appear once in a selector name. You should never end up with anything like: parent__child__grandchild__greatgrandchild. If you’re getting to great great great grandchild levels you might want to revisit your component structure anyway.
BEM naming isn’t strictly tied to the DOM so it doesn’t matter how many nested levels deep a descendent element is. The naming convention is there to help you identify relationships with the top level component block — in this case, card.
This is how I would treat the same card component:
This means all the descendent elements are only affected by the card block. So, we would be able to move the text and images into card__header or a new card__footer element without breaking anything.
Another issue commonly faced is if a component’s styling or positioning is affected by it’s parent container. This specific problem is covered in a lot more detail here and here. I’m just going to fill you in on my preferred approach.
To summarise, let’s assume we want to add a button into the card body of our previous example. Button is already it’s own component. It looks like this:
If there are no styling differences to the regular button component, then there is no problem, we just drop it in like so:
However, what happens if there are a few subtle styling differences, e.g we want to make it a bit smaller, have rounded corners, and add a drop shadow but it’s specifically only when part of a card component? I find a cross component class to be the most robust solution i.e:
The unique styling attributes are applied to card__button which lives in the with the rest of the CSS for card. This means if you decide to remove the card component, the unique button styles are removed with it, without you having to remember to do so. It’s worth putting a comment in your CSS to indicate that it is a cross component style.
Of course, the other option is to go back to your designer and tell them the button should be consistent with the rest of the buttons on the site and avoid this issue altogether… but that’s one for another day ;)
I would also apply the rule of 3 here. This means, if later on in development this same button styling crops up a further two times, then abstract it to it’s own modifier.
One of the biggest problems is deciding where a component ends and a new one begins. In our card example, you might later create another component called panel with very similar styling attributes but a few noticeable differences.
But what determines whether there should be two components panel and card or whether you simply create a modifier for card that applies the unique styles.
It’s very easy to over modularise and make everything a component. I recommend starting with modifiers but if you’re finding your specific component CSS file is getting difficult to manage then it’s probably time to break a few of those modifiers out. A good indicator is when you find you’re having to reset all the “Block” CSS to be able to style your new modifier, this to me suggests new component time.
The best way if you work with other developers or designers is to ask them for an opinion. Grab them for a couple of minutes and discuss it. I know it’s a bit of a cop-out answer but on a large application its vital that you all understand what modules are available and agree on exactly what constitutes a component.
Some components require a parent wrapper or container that dictates the layout of the children. In these cases I always try to abstract the layout away into a grid and the component is simply the contents of each grid cell. In our card example, if we wanted to layout a list of 4 cards, I would use the following markup:
Don’t be afraid to use a little extra markup to save yourself a massive headache. No-one is going to pat you on the back for shaving off a couple of <div> tags!
In some instances this isn’t possible, for example your grid isn’t going to give you the result you want or you simply want something semantic to name the parent element. In this case I tend to opt for the word container or list depending on the scenario. Sticking with our cards example, I might use <div class=“cards-container”>[…]</div> or <ul class=“cards-list”>[...]</ul> depending on the specific use case. The key is to be consistent with your naming convention.
This is a common problem, particularly when styling a component in an active or open state. Let’s say for example our cards have an active state, so when they’re clicked on they get a nice border styling treatment to make them stand out. How do you go about naming that class?
The way I see it you have two options really, either a standalone state hook or BEM like naming as a modifier:
BEM has been an absolute life saver for me in terms of creating applications in a modular, component driven way. I’ve been using it for around 2 years now and these were the few stumbling blocks I’ve hit along the way. I hope you’ve found this article useful, and if you’ve not given BEM a go yet, I highly encourage you to do so.