Atomic CSS takes a markedly different approach from BEM. Named and explained by Thierry Koblentz of Yahoo in his 2013 piece “Challenging CSS Best Practices”, Atomic CSS uses a tight library of class names. These class names are often abbreviated and divorced from the content they affect. In an Atomic CSS system, you can tell what the class name does—but there’s no relationship between class names (at least, not those used in the stylesheet) and content types. Today, Tailwind CSS and Tachyons use a similar approach.
Let’s illustrate with an example. Below is a set of rules in what we might call a conventional CSS architecture. These rule sets use class names that describe the content to which they apply—a global message box, and styles for “success”, “warning”, and “error” message boxes:
msg {
background-color: #a6d5fa;
border: 2px solid #2196f3;
border-radius: 10px;
font-family: sans-serif;
padding: 10px;
}
.msg-success {
background-color: #aedbaf;
border: 2px solid #4caf50;
}
.msg-warning {
background-color: #ffe8a5;
border-color: #ffc107;
}
.msg-error {
background-color: #faaaa4;
border-color: #f44336;
}
To create an error message box, we’d need to add both the msg and msg-error class names to the element’s class attribute:
<p class=”msg msg-error”>An error occurred.</p>
Let’s contrast this with an atomic system, where each declaration becomes its own class:
.bg-a {
background-color: #a6d5fa;
}
.bg-b {
background-color: #aedbaf;
}
.bg-c {
background-color: #ffe8a5;
}
.bg-d {
background-color: #faaaa4;
}
.bc-a{
border-color: #2196f3;
}
.bc-b {
border-color: #4caf50;
}
.bc-c {
border-color: #ffc107;
}
.bc-d {
border-color: #f44336;
}
.br-1x {
border-radius: 10px;
}
.bw-2x {
border-width: 2px;
}
.bss {
border-style: solid;
}
.sans {
font-style: sans-serif;
}
.p-1x {
padding: 10px;
}
That’s a lot more CSS. Let’s now recreate our error message component. Using Atomic CSS, our markup becomes:
<p class=”bw-2 bss p-1x sans br-1x bg-d bc-d”>
An error occurred.
</p>
Our markup is also more verbose. But what happens when we create a warning message component?
<p class=”bw-2 bss p-1x sans br-1x bg-c bc-c”>
Warning: The price for that item has changed.
</p>
Two class names changed: bg-d and bc-d were replaced with bg-c and bc-c . We’ve reused five rules. Now, let’s create a button:
<button type=”button” class=”p-1x sans bg-a br-1x”>Save</button>
Hey now! Here we’ve reused four rules and avoided adding any more rules to our stylesheet. In a robust atomic CSS architecture, adding a new HTML component such as an article sidebar won’t require adding more CSS (though, in reality, it might require adding a little bit more).
Atomic CSS comes with a few advantages:
- it keeps CSS trim by creating highly granular, highly reusable styles, instead of a rule set for every component
- it greatly reduces specificity conflicts by using a system of low-specificity selectors
- it allows for rapid HTML component development once the initial rule sets are defined
Atomic CSS is a bit like using utility classes in your CSS, but taken to the extreme.
1. The Case Against Atomic CSS
Atomic CSS runs counter to much of the popular advice about writing CSS. It feels almost as wrong as sticking style attributes everywhere. Indeed, one of the main criticisms of the Atomic CSS methodology is that it blurs the line between content and presentation. If cLass=”fL m-1x” floats an element to the left and adds a 10px margin, what do we do when we no longer want that element to float left?
One answer, of course, is to remove the fL class from our element. But now we’re changing HTML. The whole point of CSS is to separate markup from presentation. Still, updating the HTML may be a small price to pay for rapid component development and trimmer CSS.
In Koblentz’s original post, he used class names such as .M-10 for margin: 10px and .P-10 for padding: 10px . I hope the issue with such a naming convention is obvious. Changing to a margin of 5px or 20px means we’d need to update our CSS and our HTML, or have class names that fail to accurately describe their effect.
Using class names such as p-1x , as done in this section, resolves that issue. The 1x part of the class name indicates a ratio rather than a defined number of pixels. If the base padding is 5px (that is, .p-1x { padding: 5px; } ), then .p-2x would set 10px of padding. Yes, that’s less descriptive of what the class name does, but it also means that we can change our CSS without updating our HTML, and without creating a misleading class name.
An atomic CSS architecture doesn’t prevent us from using class names that describe the content. You can still add .button_ dose or .accordion_trigger to your code. Such class names are preferable for JavaScript and DOM manipulation.
2. Know When to Go Your Own Way
In practice, your CSS will include a mix of approaches. You may have class names that describe content or components in addition to utility class names that describe color and layout.
If you don’t have full control over the markup, as with some CMS products, neither of these approaches may be useful. You may even need to use long and specific selectors to reach your design goals.
Source: Brown Tiffany B (2021), CSS , SitePoint; 3rd edition.