Jacket Mel amp; winter Jo Leisure Hwz8p6q

It's not a stretch to say that BEM is the most sought-after naming convention for CSS, yet despite its popularity it can still be misconstrued by even the most seasoned of developers. It's not perfect, granted, but it's a methodology that in the right hands can see a project's CSS blossom into a garden of delightfully scoped components.

In a recent post, I wrote about how you can utilise BEM to create a responsive timeline. I touched on the idea of "grandchild elements", an area that I've seen a lot of developers struggle with, and I wanted to delve deeper into that subject.

At a base level, BEM provides us with the following practices for CSS selectors, each correlating to a different letter in its name:

B: Block - A standalone entity that is meaningful on its own.E: Element - A part of a block that has no standalone meaning and is semantically tied to its block.M: Modifier - A flag on a block or element. Use them to change appearance or behaviour.

Notice that everything is tied to the 'block'? Well, grandchildren kind of break that rule.

Grandchild elements are the idea that a component may have elements within elements. That's to say, an element may be tied to another element, rather than the block itself.

If we did require that functionality, then we'd need to extend the BEM methodology to allow for this. Or, perhaps there are better resolutions? It's a tough one to answer and there's no one rule fits all.

To demonstrate, here's a post from Assortment's home page:

A typical blog post excerpt on Assortment

winter Jacket Jo Leisure Mel amp; and if I were to mark some of that up in HTML:

Going back to the image you'll notice that on mobile the category label and date are centered at the top of the component, whereas on desktop they're positioned on the top left. To allow for this, I wrap them both in a .post__meta element which handles the positioning thanks to some media query goodness.

What gets interesting is how we should then mark up the contents of .post__meta, that being the category and date. There are a few approaches we can take, each having their own pros and cons. Let's dive in.

Our first option is to flatten our grandchildren. Flattening would mean treating them as though they have no relationship with their parent element, despite the tree representing this. Essentially disregarding the notion of grandchild elements altogether.

Whilst a simpler approach, it does decrease the readability of the component moving forward. In the example above, there would be no indication to another developer coming onto your project that the post__date element is to always be wrapped in post__meta, and so could lead to misuse of the component unless external documentation is available. This, in turn, would increase the time it takes for a developer to consume the component correctly, as they now have to the read documentation beforehand.

In an ideal world, we would want the hierarchy to the component to be understood from the CSS selectors alone, which would not be the case here. That being said, there are occasions where this approach could be preferable.

If a component were part of a wider design system where documentation is already required for consumption, then it's probably not a big deal for developers to take the extra few seconds to read a few lines on what should be nested within what.

In circumstances where a grandchild has the ability to be in multiple places within the component, depending on the design requirements on that page, it can be better to ignore a potential relationship with its parent.

To give an example, what if there were multiple instances of a post's date? We've already established one instance on the home page, but perhaps there's another variation on the post's individual page, that's styled ever so differently. At that point, your element now has multiple ways to be consumed and there's no easy way of explaining that to a developer through any naming convention. At that point, I'd probably go with creating a whole new block.

As with Flattening, creating a new block doesn't actually achieve any relationship between elements and again dismisses the idea of grandchildren, however, it does provide you with a more robust platform to start from. Whether that's needed or not is the main question.

Many developers I've spoken to go with this option as in their eyes if you're required to have a relationship between elements (grandchildren), then your component is probably too complex. Instead, you should separate your concerns and use external documentation as required to explain any relationships of how a component links with another.

In our example above, any category styling would be part of the category namespace, whereas positioning in the post would be done by post__category. This also has the added benefit of ensuring your component isn't tied to any positioning on the post, which is useful if you need to reuse this somewhere else on your website (as I mentioned above).

However, you're not going to want to create a new block for every single element that could do with a small bit of upfront information to developers that it's nested within another element.

One of the more popular examples of grandchild elements I see is extending the element syntax (__element) a step further to include it's children.

This nicely ticks the box of allowing the structure to be described through the HTML and more importantly seems the be the first solution a lot of developers come up with so it potentially has some innate learning built in.

That being said, it’s still an extension to the BEM convention and so has a slight overhead for developers coming onto a project with this in place.

The hyphenated approach could be considered both an extension of the naming convention and flattening the idea of grandchildren at the same time.

In the BEM specification, it explains that names with multiple words should be written using a hyphen to represent the space. So you could break .post__meta-category down to:

post being the block;

and meta-category as a double-barreled element.

New developers (who’re only familiar with the traditional BEM syntax) won’t be confused and it still conforms to the specification whilst providing the ability to create a nested structure of elements in our selectors.

Of course, we know the true intentions of meta-category, but that's OK. It'll provide us with all the functionality we're looking for without confusing new developers coming onto the project.

The only real downside I've noticed when using this approach is if you start mixing double-barreled element names with grandchildren and how you distinguish between them both. Though to be honest, I can't remember the last time I had a double-barreled name for an element.

If all else fails, there's no harm in extending the BEM syntax altogether.

In the example above I use a single underscore to describe a grandchild element, however, there's no reason it couldn't be three hyphens or a completely new character altogether. (Just keep in mind that if you use a special character you'll need to escape it in your CSS.)

Again, this approach would introduce an initial learning curve for your developers, but going back to the idea of a project which requires external documentation from the get-go, you may not mind a little overhead.

That's the real question, isn't it? I've laid out a few options, but which should you choose? The truth is, I don't know. Like everything in web development, it completely depends on your project and use case.

What I will say is this. Try to limit the times you're extending BEM to a minimum to avoid unnecessary complications to your naming convention. With the times that you do have to extend, ensure your entire team is onboard with a single strategy you're going to use throughout the project, and stick to it. Consistency is more important in my opinion. There's nothing worse than a codebase that doesn't conform to the original methodologies agreed.

Oh, and remember, nobody's going to judge you because you're not conforming with a specification to the tee. Most specifications are built on the extensions of others so if you have a use case then embrace it and look for a solution that suits yours and your project's needs.

Luke Whitehouse

Hi Kirsty,

Glad you found the article useful. I'd definitely still advocate the use of normal modifiers using the double hyphen syntax --. This article is more on extending what BEM already provides.

What I would say though is in your example you reference .block--red. Whilst fine, I'd try and name my modifiers based on the type of modifier, rather than the value it's given. For example, let's say we went with a modifier of --red and the next day you're told to change it from red to purple, then you'd need to not only change the CSS but also the class name, or create a new one. This either creates bloat in your CSS or unneeded time taken to complete. Instead you could go with something like block--primary which wouldn't have to change if the value does.

Jan Z

For block elements, I always use -- instead of __ (underscore) like you're supposed to, because block_name--child_name makes both names much easier to select using a double-click. Double click selection usually includes strings that are connected with underscores, but not dashes -, creating a sort of "selection wall" with dashes.

I also use a leading underscore to denote an element type, separately from the name.

And for properties or modifiers like red or big or bold I usually use separate --red--big--bold flags. This works well because your properties can be treated separately from the block and element type, and in my SCSS I can just define --big relative to whatever block it describes.

Here's an example:

class="checkout--payment _button --large --wide --red

This element is part of checkout, and is the payment child. _button denotes it's a button style, and each separate modifier describes how the _button should look. This system makes building prototypes and interfaces incredibly fast for me.

Luke Whitehouse

Hi Jan,

Thanks for your comments. I know all too well what you mean regarding the underscores getting selected whereas hyphens don't. It's been something of a bug barer of mine for a long time. The only worry with changing something fundamental in BEM is the learning curve for developers. Granted it's an easy thing to change, but for me it's pretty baked into how I write my selectors these days that I'm sure I'd make mistakes.

Regarding your other comment on having --big and --large selectors on their own without the block attached is slightly separate to this topic. I have seen this approach and I understand why you might use it, however, I have my concerns. Namely being the CSS that is outputted will increase a lot in specificity, something that the normal implementation of BEM keeps level so well.

Luke Whitehouse

Looks great to me, just remember there's no one-size fits all rule to grandchildren. Whilst the majority of time creating a new block is preferable, there are occasions where you'll find a use for grandchildren as I've mentioned in the post.

Luke Whitehouse

Thanks for sharing your approach. I wonder if you're misconstruing the reasons for using BEM though. Here's a couple of my thoughts:

You have nested blocks

Having a .header or .footer within amp; Mel Jacket Jo winter Leisure .card without any BEM element to suggest this can lead to confusion in a team on how to consume the component.

Outputted CSS

In your example you mentioned selectors like .card .header. This means that you're increasing the specificity of your outputted CSS, whereas a normal BEM element such as .card__header wouldn't. This could then lead into having .card__header .header in your HTML and then creating a new block for header specific things, although this isn't really the best example as .header can be interpreted in multiple ways.

Lisa

Thanks for the great article! I began trying to use BEM about half a year ago now and have still been struggling with this particular scenario. I've tried the hyphen spacing but since it was so similar in look/shape to the modifier format, I found it confusing when trying to quickly glance through markup. I like the idea of having class='block__grandchildBlock grandchildBlock' element with 'grandchildBlock__element' children. I think that makes the most sense and allows for overall styling of the grandchild block type using just the 'grandchildBlock' class name and 'block__grandchildBlock' as an almost reverse-positioned modifier. This is probably something I'll try next :D thx!

Luke Whitehouse

Hi Lisa, glad to hear you've taken something from this post. Generally speaking, I'd say a new block is the best way forward so do go with that approach and please let me know if you have any problems, I'd be happy to help!

Dan Donald

Nice article, Luke.

My take FWIW... not everything needs to be BEM. Only when that meets the needs of a pattern does it make sense. In these examples, it’s the familiar problem of look component-level in, which is part of the issue. Start from the smallest meaningful blocks first and assume reuse rather than binding to a full component pattern. In my experience that does often get around the grandchild problem as the only need a relationship with the component for specific positioning and not in every case.

Trying to be as OOCSS as makes sense to often helps with BEM too as you get a lean architectural object and use modifiers to skin or create variants.

Always really interesting to see others’ approaches. Like you say, there’s no absolute in the way we interpret this stuff!

Luke Whitehouse

Hey Dan, hope all is well?

I completely agree with what you're saying. Generally speaking we'll working with BEM as a methodology but also combine it with other principles such as Atomic Design being the big one. That way, you can start off with the smaller base components and build up to much larger pieces of functionality. Perhaps that would be a good follow up blog post come to think of it.

That being said, I would still recommend sticking with a single methodology, whether that be only BEM or a mixture between BEM, SMACSS and Atomic Design which we do at Sky UK. Using a different methodology for different teams/projects could lead to a number of problems such as:

Luke Whitehouse

@Dan I really need to extend my comment section functionality!

It sounds like we're in the same boat then. As with any convention, it's just that, a convention, and I'm sure we've both seen many people use BEM for unintended purposes rightly or wrongly where there are other options.

I guess the main point of all this is it depends and don't just blindly follow because someone on twitter tells you you should.

That maintains the BEM convention, while also giving you the option of specificity when needed. But honestly, you don't need to do that. In-fact, I think it's important to not think of BEM as a representation of your DOM tree. In this scenario, I would probably do this:

Luke Whitehouse

Hi Bobby,

Thanks for the suggestion, it's a good point. BEM blocks can be mixed where appropriate to provide that extra layer of flexibility and this can indeed alleviate the need for grandchild elements. My only concern with this approach is a similar one with some of the one I mentioned in my article – context. There's no relationship between these blocks for developers to latch onto, which would call for external documentation. Now as I said in the article, perhaps that isn't a problem for teams who require docs in the first place, but for smaller teams that may be a deal breaker.

In addition, depending on how you code the components and their use case, you may never be able to use a block without another. That to me defeats the purpose of the BEM methodology and the problem we're trying to solve.

Nonetheless, a good alternative for certain circumstances and on a whole combining blocks can be very powerful. See Atomic Design for that.