What the class?
How to pick better class names for you HTML tags
I’ve recently been asked about what class names one should use. It’d been a long time since I last had to think about it, but it was a good refresher for me, and an opportunity to summarize my thoughts. I decided to jot down some notes about the topic in case anyone else is interested. I suspect it may not be as obvious as most people think.
Where classes come from
The first thing to note here is that I said pick class names “for your HTML tags”, not “your CSS declaration blocks”. Depending on how you go about doing CSS, you can either see classes as coming “from CSS” or coming “from HTML”.
The first approach, picking class names for the declaration blocks, treats the CSS declaration blocks as a labelled library function, where this “function” is “imported into HTML” via the class attribute.
The second approach, picking class names for the HTML elements, treats the classes as labels given to a set of elements that share the exact same role in the content that are then selected in CSS and assigned to declaration blocks.
I consider the latter to be the correct mental model. At the very least, it is closer to how CSS is explained in the relevant documentation:
[…] describe the presentation of a document […]
This is a big shift for most developers. I think it’s a worthwhile one, though, because…
Using “structural” class names
Class names can describe or label the content in the context of the document, rather than the appearance of the content. For instance:
<ul class="skills">
...
</ul>says a lot more about the list — with a lot less, too — than:
<ul class="vertical-flex text-size-regular bg-grey">
...
</ul>I call the first convention “structural class names” (or just “correct class names”) as opposed to the latter “presentational class names”.
There are three advantages of using the structural class names.
Firstly, the structural class names are easier to come up with, because they are simply labelling the content rather than some abstract visual concept. (It also help when developers aren’t very familiar with UX concepts, and end up with names like box.)
Secondly, and more importantly, it makes it easier to maintain the code. For example, let’s say you have <span class="text-grey text-small"> to describe the last known price of a discontinued product. If you later decide to change the color of the price, you need to either invent a new class for it, or you have to rename the class name, and change it everywhere in the HTML and CSS. It’s a lot simpler if you simply use <span class="last-price"> and update just its appearance in the CSS. This also drives the point home about separation of concerns, as the changes to the presentation should be ideally confined to CSS if you’ve got the separation right.
(I won’t even comment on the CSS-in-JS type of setups. People using such systems have bigger issues to address than what naming convention they would like to use.)
Thirdly, since not every user agent is going to take advantage of the visual appearance of your document (bots, braille readers, text-only browsers), it reduces the total amount of HTML these agents need to go through if you can express things with less classes. Structural classes usually require less HTML code because applying different aspects of the appearance is done entirely in CSS rather than in both CSS and HTML.
Code reuse with structural classes
One issue developers tend to run into when using structural classes is code reuse. Going with the aforementioned .last-price example, let’s say our styling of choice is this:
.last-price {
font-size: 87.5%;
color: var(--muted);
}Now, let’s suppose we decided that something else on the page should also have the same styling. For example, .date-discontinued. If we apply the .last-price class to that element, then we’re breaking the semantics of the page (at least for the fellow developers, browsers couldn’t care less). Because of that, developers tend to want to rename .last-price to a more generic name that would cover both of these use cases, like .small-grey. That’s how presentational classes are born. What we can do instead is to just add the other selector to the same declaration block:
.last-price,
.date-discontinued {
font-size: 87.5%;
color: var(--muted);
}This is why I keep saying that the unit of reuse in CSS is the declaration block. We are reusing this part:
{
font-size: 87.5%;
color: var(--muted);
}and not the selectors. Selectors are specific to the document structure, not generic reusable labels.
Let’s suppose we later change our mind about the font size of the .date-discontinued. We can then simply factor the no-longer-shared declaration out of the block.
.last-price,
.date-discontinued {
color: var(--muted);
}
.last-price {
font-size: 112.5%;
}
.date-discontinued {
font-size: 87.5%;
}The last example also shows how you can separately describe different aspects of the appearance of a single element (or a single set of elements) on the page.
(Note that I’m not advocating for single-property declaration blocks. That’s just a consequence of the simplified example code. I could theoretically do single-property blocks — let’s call those… ehm… “utility blocks” (ducks to dodge a tomato)— but that just complicates the code way too much for me. Some repetition goes a long way towards preservation of sanity.)
This style of CSS reuse also mostly does away with the need to do overrides, and does not require complex naming systems like BEM. The main purpose of BEM and similar mechanisms is to makle overrides easier by reducing the specificicity of your selectors. If you can avoid overrides to begin with, you don’t have to worry about specificity! Wonderful.
There’s one scenario where this reuse model falls apart, and that’s UI toolkits (UI libraries). If you’re building a CSS UI library (like Bootstrap, for example), you cannot do this kind of reuse because you have no awareness of the content structure ahead of time. Sadly, I have no good advice for you in this case. Maybe you have some for me? (CSS really does need native mixins.)
When to use classes
Classes are only one way to select elements, and there are many many more. You don’t necessarily need to use classes. There is no inherent advantage in using classes over other selectors. There used to be a time when using complex selectors caused a tangible performance impact, but that’s no longer the case. Most selectors are quite well-optimized these days.
On my last project, I only actually needed a handful of classes, and everything else was selected using id, combinators, and pseudo-selectors. I suspect that, if you give it enough consideration, you can get rid of most classes.
Here’s a few examples of things to consider before even reaching for the classes.
- Is it the only element on the page? Can you just use an
idto select it? - Does the existing HTML structure allow you to reach the element using combinators?
- Did you overcomplicate the document structure and are using the classes to compensate? Can you improve the structure? (Because if you can’t, you might as well just use classes.)
- Are you trying to style a specific state of the element? Can you use an existing selector for that state:
:disabled,:checked,:invalid,:not([open]),[data-mode="active"],[aria-hidden="true"]…?
Sometimes, classes are the right type of selector, though. If I thought otherwise, I wouldn’t be writing an article about what to name them, now, would I? 🕵️♀️






