BEM

Best practice for naming classes with HTML/CSS.

What is BEM?

BEM is a well-known method of naming components, it stands for Block, Element, Modifier. The following is a short introduction to BEM, but if you are comfortable with BEM, skip to how Listers uses BEM in a slightly different manner.

.block {}
.block__element {}
.block--modifier {}

Block - The sole root of the component.

A block represents the main component name. If you were building a house component, the class name would be .house class.

So far we have:

<div class="house">...</div>

Element - A Component part of the block

An element represents a part of a component and is separated by two underscores. The door of the house would be represented by the class .house__door. A window would be .house__window.

<div class="house">
<div class="house__window">...</div>
<div class="house__window">...</div>
<div class="house__door">...</div>
</div>

Be careful to look for smaller component possibilities within a larger component, especially if it's a pattern that might be repeated in a unrelated component. Avoid using a class like .house__stair__step and rather .house__stair-step.

Or if the stair portion of the component might be used inside another component, make the .stair a smaller component within the large component and use .stair__step as an element of it.

So far we have:

<div class="house">
<div class="house__stairs">
<div class="stairs__step">...</div>
</div>
<div class="house__window">...</div>
<div class="house__window">...</div>
<div class="house__door">...</div>
</div>

<div class="shed">
<div class="shed__stairs">
<div class="stairs__step">...</div>
</div>
<div class="shed__window">...</div>
<div class="shed__window">...</div>
<div class="shed__door">...</div>
</div>

Modifier - A variant or extension of the block.

Since the properties that should apply to every house are place on the main .house class, all houses receive the .house class as the base. If there is a variation of a house - perhaps it is red - the .house--red class would be added to the component in addition to the .house class. If the house has a red door, a variation can be placed on the door element itself - .house__door--red.

Finishing off we have:

<div class="house house--red">
<div class="house__stairs">
<div class="stairs__step">...</div>
</div>
<div class="house__window">...</div>
<div class="house__window">...</div>
<div class="house__door house__door--grey">...</div>
</div>

BEM with a twist

In some cases, we've added to, or deviated from typical BEM naming conventions. These are outlined below:

Namespaces

We've added namespaces to our classes, this improves the class somewhat in a few different areas. It allows us to know what kind of job the class might have, how and where we might be able to use it and whether we can modify it.

Our common use namespaces are:

  • .o- for objects.

    Signifies that something is an Object, and that it may be used in any number of unrelated contexts to the one you can currently see it in. Making modifications to these types of class could potentially have knock-on effects in a lot of other unrelated places, so be careful when changing these. When creating components in your project, do not bind onto objects (in your scss) i.e. .c-hero__nav.o-nav { /*styles*/ }, because this makes them less abstract and re-usable. Objects generally have no aesthetics (aesthetics should be applied with components or themes) meaning the object has a particular purpose and is mainly for layout purposes.

    'Content' which is applied at the stylesheet level, is an exception or inclusion to the rule. Objects like breadcrumbs, which add characters like > within styles is not considered an aesthetic change and therefore can be classed as an object.

  • .c- for components.

    Signifies that something is a Component. This is a concrete, implementation-specific piece of UI. All of the changes you make to its style should be detectable in the context you're currently looking at. Modifying these styles should be safe and have no side effects other than the view you are currently looking at. We use components for things like buttons, inputs, modals and tooltips for example. These all contain opinionated design and aesthetic cues from our overall design principles and philosophy.

  • .t- for themes.

    Signifies that a class is responsible for adding a 'theme' to a view. It lets us know that UI components' current cosmetic appearance may be due to the presence of a theme. Themes should accompany a component, and change the default styling of that component. A theme class is always applied to the parent of the component you are adding the theme too. i.e. .c-hero .t-hero--blue.

  • .is-, .has- for current states.

    Signify that the piece of UI in question is currently styled a certain way because of a state or condition. This stateful namespace comes from SMACSS (which is similar to our class/css practises). It tells us that the DOM currently has a temporary, optional, or short-lived style applied to it due to a certain state being invoked.

  • ._ is used for HACKS. 😱

    Signify that this class is the worst of the worst - a hack!. Sometimes, although incredibly rarely, we need to add a class in our markup in order to force something to work. If we do this, we need to let others know that this class is less than ideal, and hopefully temporary (i.e do not bind onto this).

  • .js- for Javascript.

    Signify that this piece of the DOM has some behaviour acting upon it, and that JavaScript binds onto it to provide that behaviour. If you're not a developer working with JavaScript, leave these well alone.

Examples

From this, I can see that we have reusable abstraction, for instance, the .o-media and two implementation-specific components .c-avatar and .c-tooltip--left. These classes are all still blocks, elements or modifiers: They haven't added a new classification, but have added another layer of rich meaning.

These namespaces tie in with the layers found within our CSS architecture (which leverages the CSS cascade and is generally mobile first), meaning every class has a specific place to live in our project and within our file system.

For more information about these namespaces read this article by Harry Roberts.

Responsive suffixes

Responsive suffixes provide a way to add classes for a particular breakpoint. These suffixes take the format -<breakpointDelimiter>-<breakpoint><number>, and tells us 'this class when at this size'. There are a few different breakpoint delimiters that satisfy different scenarios with responsive design. These expressions are:

  1. .class-@bp# which means: greater than {breakpoint}{number}.
  2. .class-<bp# which means: less than {breakpoint}{number}.
  3. .class-=bp# which means: only between this {breakpoint}{number} and the next.

For example:

/** 
* From bp3 I want to apply max width 320px
**/


.u-maxw-320px-@bp3 { max-width: 320px; }

/**
* For mobile upto large tablets
* I want to be 100% width
**/


.u-w-100%-<bp3 { width: 100%; }

/**
* I want to remove this element between
* large mobiles and small tablets
**/


.u-remove-=bp1 { display: none; }

Each breakpoint delimiter should be a human readable and logical way of denoting states. It allows developers to learn about any potential permutations or appearances that the piece of UI in question might have, just at a glance.

You can see all current breakpoints available from the responsive design tokens page.

Container prefixes

With Container Queries now available in all major browsers, we can implement these by switching the class suffixes to prefixes.

This means that you can tell just by looking at the prefixed breakpoint class, that the element is due to change state relative the parent container width and *not* browser width.

  1. .@bp#:class which means: greater than {breakpoint}{number}.
  2. .<bp#:class which means: less than {breakpoint}{number}.
  3. .=bp#:class which means: only between this {breakpoint}{number} and the next.

For example:

/** 
* When the container of my component is tablet size
* set width to 100%.
**/


@container (min-width: 834px) {
.@bp3:u-w-100% { width: 100%; }
}

Just like the above media query suffixes, container query prefixes should act and read in the same way, apart from their obvious differences.

Much like the media query tokens above, we have some pre-determined container query tokens available to use.