Please stop including color names in your CSS classes.
This is a very silly class name:
.button-blue
Also silly (from Tailwind):
.bg-red-900
By specifying the color name in the class name itself, you are partially defeating the purpose of having a class at all.
If the brand team decides to change the default button color from blue to green, you have to do a search and replace on both your markup and your CSS. At that point, you might as well have put “background-color: blue;” on everything, because you’ve got to refactor everything with the “button-blue” class anyway.
The same way we don’t name our breakpoint/responsive classes “bp-900px” — instead we use “sm” and “lg” — we shouldn’t include style values like “red” and “blue” in the class name.
How should I name my color classes then, smart guy?
Here’s an excerpt from a SCSS file I recently worked on, where I was setting up some color variables:
$interface-action-color-default: #2271b1;
$interface-action-color-inactive: #59a3df;
$interface-container-padding-default: 20px;
$interface-container-color-border: #CCC;
$interface-container-border-radius: 2px;
$interface-container-border-color: #CCC;
You might not like the specifics of how I’ve named these variables. And that’s fine. (I actually wrote a minor critique of my naming convention here and then removed it for brevity).
For the sake of this article, the specifics of the naming convention are less important than the abstraction in the names. In other words: I’ve separated the actual color value from the name of the class — and that’s what’s really important.
This way, when the color inevitably changes through a brand refresh or an A/B test that shows green is always better than blue, I can just change my variables one time, in one place. Which is a big part of why we’re using classes in the first place.
My CSS classes might look something like this:
.interface-action {
background-color: $interface-action-color-default;
&--disabled {
background-color: $interface-action-color-disabled;
}
}
And here’s some sample markup:
<button class="interface-action">Edit</button>
<button class="interface-action interface-action--disabled">Delete</button>
This allows me to avoid the trap of having values like “blue” and “800” in my class names. If there are other types of actions, I’ll use class names like “interface-action-alt” or “interface-action-secondary”.
Using Tailwind themes to get more abstracted class names
I was initially put off by Tailwind’s use of color “values” inside class names. It can resolved through the use of themes, although I do wish the themes layer provided just a little more flexibility in its keys and nesting of values. But the same conventions can apply there; you can define a theme like this in tailwind.config.js:
module.exports = {
theme: {
colors: {
action: {
default: '#2271b1',
disabled: '#742a2a'
},
toolbar: {
default: '#EEE',
alt: '#CCC'
}
}
}
}
You can use the theme in your CSS like this:
button {
background-color: theme('colors.action.default');
}
button.disabled {
background-color: theme('colors.action.disabled');
}
/* Sidenote: I generally avoid styling the actual button element and
* instead opt for an abstracted class name there too, but I'm doing it here
* for the sake of example.
*/
Relevant class names are auto generated by Tailwind if you want to skip the CSS altogether:
<button class="bg-action-default">Edit</button>
<button class="bg-action-disabled">Delete</button>
It seems like a lot of work to classify all the different element types, give them meaningful but well-abstracted names, and account for variations on the defaults.
Yep. And it’s totally fine to adjust the approach if your design system simply isn’t consistent enough to practically allow for this convention. It’s a lot of up-front work to decide on how to properly name both the elements and the state they might be in (enabled, disabled, etc).
But if you’re really thinking about the architecture of your markup and CSS, I’m not sure why you’d choose to go the “color names within classes” route.