Logical class names in CSS
How to help make your code make sense
From the moment I first had to pull a CSS class name out of thin air, I wanted to know if there was a standard naming convention that could make my style sheets feel a bit less haphazard. Assigning classes felt messy because it was so arbitrary, so I was thrilled to learn that about several different methodologies for streamlining, slimming, and organizing CSS, each based on its own type of logic.
Semantic names: related to meaning in language or logic
In my earliest web design projects, the CSS class names under the hood weren’t pretty. I knew that naming was really important, but I struggled to find names that were semantic — that is, that they were actually related to the meaning or description of the tag itself.
What separates a good, semantic name from a poorly articulated non-semantic name? Well, in a nutshell, a semantic name describes the meaning of the thing — what it is or what it does. A non-semantic name doesn’t really give you any information at all. As an example, mainHeader
is a semantic name, because you can be pretty sure that it’s attached to an element that contributes to the main header. This name is clear, so even if you’re hunting through a code jungle you’ll still know where to look for the content you’re trying to track down. I like to camelCase, so I can be pretty confident that even if I can’t remember a class, I can ctrl + F
and take a shot in the dark by typing mainHeader
to find the thing that I’m looking for.
But. You might have a bunch of things that are related to the main header. You could have a div
with a class of container
that holds the header together. You might have a background image behind the header area. You might have an animation that lives in a separate div
. So all of a sudden, you’ve got a whole collection of things that are really and truly related to the header, but giving them ALL a class of mainHeader
doesn’t really make semantic sense any more.
Thankfully, other people have encountered this problem and have developed systems to deal with it. You might have heard of systems like SMACSS, OOCSS, Meaningful CSS, and Functional/Atomic CSS, but my personal fave (and generally-agreed-upon gold standard for class names) is BEM.
BEM stands for Block, Element, Modifier, and its general principle is to create clear and direct connections between HTML (the semantic part of the page) and CSS (the decorative part of the page).
Class names in BEM all follow the same convention:
block {}
block__element {}
block__element--modifier {}
Block: the block is the parent, and the name that describes your component at the highest level. Sometimes (often), the block name will be the same as the name of the HTML element — and if that’s what does the best job of describing the element, why mess with it? These high-level names also allow for reuse of code, because they’re broad enough to adapt to different parts of your page. Some examples of block-level classes are:
button
(orbtn
, and you can see how this can adapted to any button on the page)navigation
(ornav
, which is great if you want a main nav and a sub nav, for example)header
(but notmainHeader
, because this limits where the element can be reused. Avoid giving block-level names that describe the location of an item; it’s best to stick to the function instead)
Element: the element is officially defined as the child part of a class name that depends on the block and cannot be used without its parent. The element is written after the block and separated by two consecutive underscores. I like to think of it as describing the type of thing that the block is — for example, header__main
tells me that I have a header, and this is the main header (there might also be header__section
or header__aside
, both of which reuse the header
block nicely).
If we look at the button example, you could have a button__form
or a button__animation
, both of which we can tell are buttons but have purposes that are clearly defined.
Modifier: here’s where we get specific! The modifier describes the appearance or behaviour of an element. If there are two versions of your main header (to be used on light or dark pages), BEM methodology would label them as header__main--light
and header__main--dark
. In the button example, we might have button__form--submit
and button__form--clear
.
Getting used to BEM can be tricky, especially if you’ve been following the wild west naming system (featuring such renegade class names as redTitle
and bottom-photo-large
). And I’m the first to admit that BEM can get a bit unwieldy and unattractive. But when you’re trying to write DRY code that can be reused, is easily adaptable, and won’t elicit a million questions from your team? That’s where BEM wins.
*Note that there are several naming conventions that are based on/inspired by BEM. If you’re not crazy about the specific rules of BEM but like the overall concept, I’d suggest you have yourself a little Google — people are coming up with BEM variations all the time, and you’re bound to find one that makes things clear to you.