How and why I use BEM-like syntax

My experience with HTML & CSS goes back about 11 years – these are the very first languages I started working with and were basically my introduction to code. I work with them just about every single day of my life and have probably spent too much of my time thinking about them. They aren’t difficult languages to learn and are quite easy to work with but, as with anything, they have their issues and these issues tend to become more apparent the larger a project becomes.

Whilst I had always tinkered and experimented with HTML/CSS frameworks like Bootstrap, I never really adopted them for any projects as I always found maintaining my own boilerplate and toolset to be as flexible (if not more). Of course, by not adopting someone else’s framework, my own kind of grew and evolved and eventually had a lot of variation in it’s syntax. This variation would often make things a little confusing and harder to read, which is ultimately frustrating and has a negative impact on productivity. So, at some point along the way, I decided to adopt some kind of standard and in my reading, I came across BEM – Block Element Modifier.

These days, I use BEM all the time. In fact, I don’t think I ever write HTML and CSS any other way, as this just makes so much sense to me and serves my component-driven approach well.

What is BEM?

BEM (Block Element Modifier) is basically just a naming convention for classes in HTML & CSS. The convention offers a semantic approach for grouping related HTML elements into components (Blocks). Blocks can contain any number of elements and, when you look at the HTML, it’s easy to see which elements belong to a block. Let’s take a look at a really simple block which has one modifier and contains two elements;

<div class="PostCard PostCard--is-feature">
    <h1 class="PostCard__title">Post title here</h1>
    <div class="PostCard__content">Post content here</div>
</div>

At a glance, I can see that all elements here belong to the PostCard block. The CSS for this block would look something like this;

.PostCard{}
.PostCard__title{}
.PostCard__content{}
/* the cascade comes into play when the block modifier needs to alter an element */
.PostCard--is-feature .PostCard__title{}

This is a rather simple example, but it demonstrates the clarity in the markup and the lean nature of the CSS selectors. For a more detailed intro, I suggest checking out the introduction at Get BEM.

Why use it?

Here a few really nice benefits of using something like BEM;

  • The BEM syntax helps facilitate modular code that is easy to parse and the relationship between markup elements becomes a lot easier to understand.
  • Helps reduce cognitive load by;
    1. reducing the need to think about element relationships
    2. reducing the need to compare your CSS and HTML to work out what is going on in the CSS file/s
    3. offering greater meaning to your HTML at a glance. e.g; when I see an id="" attribute in my markup, I know it isn’t for CSS and is more than likely a JS hook
  • BEM blocks are nicely portable which makes them easily reusable from project to project.
  • BEM produces relatively flat CSS where most elements will have one single selector. This helps us avoid issues that can occur with the cascade and rarely requires the use of the !important keyword.
  • I’ve read a little on the possible performance gains of CSS rendering, but I don’t have any facts/stats around this. Instead, I will say that it can greatly reduce your CSS if your CSS tends to end up with selectors that run many levels deep.

How my approach differs from the traditional BEM defined syntax?

If you go and read about BEM and compare what you read to my examples, you’ll notice there are a few differences;

1. I use StudlyCaps for my block names

Some people will cringe at the use of capitals in this context, but I find it makes my blocks very clear while cutting down on hyphens.

2. I use global modifiers where appropriate

e.g; -pull-right I do this because there are some things that I really don’t think I need to define on every block. When I see a class prefixed with a hyphen, I know it is a global modifier.

Keeping it easy with pre-processors like Sass

Now, you might be thinking something along the lines of “Gee, BEM really bloats those CSS classes…I don’t want to be writing all that out!” To be honest, I wrestled with this a bit myself as well, but after a lot of use, the benefits really have outweighed that little argument.

In my dev workflow, it’s rare that I actually touch raw CSS – I’m almost always using Sass to generate my CSS and, when it comes to writing BEM components, Sass really starts to shine for me. Allow me to explain;

I can use a single variable for defining the block name which keeps things nice and DRY. e.g;

$module: '.PostCard';
#{$module} {
    &__title {}
    &__content {}
    &--is-feature{
        #{$module}{
            &__title{}
        }
    }
}

That is how I write simple components on the fly, but I’ll normally take things a step further by defining base mixins;

// the base mixin - no actual CSS goes in here
@mixin PostCard {
  $module: '.PostCard';
  #{$module} {
    @content
  }
}

// the default style mixin
@mixin PostCard--default {
  &__title{…}
  &__content{…}
  
  &--is-feature{
    @include PostCard{
      &__title{…}
    }
  }
}

// default usage
@include PostCard{
    @include PostCard--default;
}

By defining base mixins, I can then compose them when I’m in a situation where one component affects another depending on their contextual relationship;

// lets say that a Features block adjusts the style of any 
// PostCard blocks contained within it
@mixin Features{
    @include PostCard{
        &__title{…}
    }
}

Some handy lessons I’ve learned along the way

  • When targeting BEM with JS, always use the full class names.
    • There are tools out there that will allow you to treat your blocks as objects and target elements within a block just by the element name, but this can break down when using minification, as the full class name isn’t there for reference/replacement.
  • If you want leaner output, use a post-processor (minifier) that replaces all your long classnames in your HTML, CSS, and JS with something less-readable, but much shorter.
  • Don’t abbreviate where the abbreviation isn’t universally understood
    • I avoid abbreviations where possible as I can never misinterpret the full word.
  • Don’t go any deeper than one element in a BEM class name – it’s BEM, not BEEM or BEEEM
    • When you start using it, this can seem like a good idea at first because your CSS can illustrate your block’s structure, but it tightly coupling your CSS rules with your DOM structure leaves you with a brittle UI.
    • Keeping it to one element makes it easier for you to change the structure of your markup (move elements around within the block) without necessarily having to change your CSS.
  • Don’t target HTML elements with your CSS – give everything a class
    • As above, this couples your CSS with the semantic structure of your DOM, leading to a brittle UI.
    • By giving every element a class, you can then easily change the element itself when required without necessarily having to change your CSS.

Conclusion

I’ve found BEM to be incredibly handy in breaking down my workload into focused little components. It reduces the amount of thinking I need to do which alleviates my overall stress level and allows me to work longer before fatiguing – the more expressive my code is at a glance, the less I have to think about it.

I’d say that my favourite thing about BEM is its tendency towards component-driven development. It’s a concept I’ve been working with a for a long time in PHP and JS, and to be able to apply that to my HTML and CSS is a dream as it means I can build complex sites from existing code that I can then reuse again and again.

If BEM isn’t right for you, there are, as always, a whole bunch of alternatives out there for you to choose from – it’s just a case of you finding the one that fits your workflow best.

Need a website? Let's talk.

From website design & SEO through to custom WordPress plugin development. I transform ideas into dynamic, engaging, and high-performing solutions.
Subscribe to get the latest insights & updates in the world of web and how it impacts your business and website.
© 2024 Phil Kurth  |  All rights reserved.