Semantic class names: are you being too generic?
Make no mistake. Naming class names is difficult. It’s no coincidence that I discuss semantic class names early on in MaintainableCSS.
In that chapter, I explain that you should name your module based on what it is. Not what it looks like or how it behaves. Even if you’re sold on the rational, there’s still plenty of room for error.
Even if you avoid stylistic and behavioural class names, you can still get your knickers in a twist. In my experience, your class names will be either too generic or too specific.
Most developers choose generic class names. In theory, this is a good because the more generic the class name, the more reusable it is. In reality it’s not so simple.
To show you what I mean we’ll build a login form together. This form consists of an email and password field.
To start, you could name these fields as follows:
These class names are specific and coupled to the login form module. This is good because you can style this form without affecting other forms.
Also, you could style this form to be consistent with the other forms on your site. Either by using a mixin or by comma-delimitting selectors:
/* Common styles for container */
/* Common styles for fields */
Depending on the site, you may end up with a lot more CSS which seems a bit unnecessary.
For example, you could name the fields more generically. Perhaps
.loginForm-field would work better.
This still seems too specific because they’re unnecessarily tied to the module. But these styles are worthy of being modules, as they’ll look the same across all forms. After-all consistency is an aspect of good design.
If we make both of these fields the same module, then we should probably name that module
All three of the class names follow the MaintainableCSS principles. But they have significant differences in how they impact the maintainability of your codebase.
Let’s find some more problems with this generic, reusable
What if there are some occasions that need a slightly different
.formField such as one that must accommodate a hint? And, what if each field that has a hint needs extra or different styles?
This is where modifiers come in. You add an extra class name to the element and make the required tweaks.
<div class=”formField formField-withHint”>
<p>The hint goes here</p>
In this example we just need a few tweaks but what if we had something more significant, such as a field that contains a set of radio buttons?
Using a modifier is problematic because there is little to inherit. When we were thinking about
.formField we didn’t consider radio buttons at all did we?
This isn’t a bad thing. In fact, I think in many ways this is a good thing. Often we can trip ourselves up trying to combine different things into one before we understand the requirements of a design system.
Technically speaking, you could name all elements
.item because everything is an “item”, but this is not practical or useful.
A set of radio buttons is different to a text field. It would have a legend, a fieldset, and a different look and feel. In reality, they are so different that despite both being form fields, we shouldn’t consider them to be the same. And this is a major point worth pondering over.
It is at this point that it becomes clear that
.formField is too generic. I certainly don’t want to update styles for a set of radios, and worry that I will regress styles in a text field. I also don’t wish to work out the few bits of commonality between these two entities to shave a little CSS.
So where does this leave us?
We’ve gone from too specific to too generic, and we are trying so hard to do a good job.
.formField is too generic and
.loginForm-field) is too specific then where do we go from here?
Having navigated through these problems in detail, it is much easier to work out a better name. It would make sense to call the text field
.textField and the radio group field
.radioGroupField and just treat them as the distinct modules they are.
They are specific enough to be able to differentiate, yet they are generic enough so the we can use them many times across several forms, without writing unnecessary CSS.
The real problem is that we face decisions like these all the time. We have to rigorously and frequently consider these problems.
This is why I sway towards being too specific because I’d rather have a little more CSS with the flexibility to style elements consistently or differently (whatever the case may be), than to get caught up with overrides and regression. I am not saying this is “perfect”. But that’s why I do it and why I advise it.
Being specific also gives you the time to learn what is worth abstracting and what isn’t. You might come to learn that even
.textField is too generic in that you might have many different types of text fields that are better off being their own modules, you might not.
The takeaway here is to think and ask questions frequently and rigorously:
1. What if a module is used in lots of places but sometimes it can look a bit different for reasons such as proximity, location, contents etc?
In this case, you’ll probably benefit from a modifier.
2. What if a component can be used frequently, pretty much as is, elsewhere?
In this case, abstract into a module but be careful not to name it too generically.
3. What if you’re spending a lot of time writing many different modifiers or working out what to abstract as common styles?
In this case, it’s probably named too generically. Split up into separate dedicated modules.
The process of naming is challenging, but after all, it is just a name and as you can see, the benefits (or consequences) of naming are quite far reaching. The good news is that if you’re conscious from the beginning, you can avoid the problems that are born out of either being too generic or too specific.
P.S. I first sent this out to my private email list. If you want in, you can subscribe here.
Thanks for reading — if you enjoyed it, please hit the ♥ button below.