There is an annual developer survey called State of CSS which explores which tools developers use to produce CSS code, what are the current industry preferences and sentiments.
Looking at the results of section "CSS frameworks" a Tailwind has been an indisputable leader in satisfaction rankings for consecutive 4 years from 2019 to 2023, meaning it has been so since its initial release in May 2019. No wonder it accumulated usage rankings throughout these 4 years from 6% in 2019 to 50.5% in 2023 making it the 2nd most popular CSS framework after Bootstrap.
I would not call myself a huge fan of Tailwind and to be honest I was a bit skeptical about it for quite some time. But I think I understand the appeal to it. In this article I will try to explore why Tailwind and other utility CSS solutions are so popular and what I think the future holds for it.
Let's get back to 2013 when the first commits to Basscss were made public. While traditional CSS frameworks at the time focused on certain components, like alerts, inputs, modal windows, etc., Basscss took a different approach focusing on abstract non-semantic utilities.
For instance, take a look at Bootstrap. It has alert which is a certain semantic component with a well-defined purpose. There are even more complex components like dropdown and components that combine multiple ones, but there is always semantics in mind. It's almost impossible to reuse the parts of alert component in a dropdown - it doesn't make any sense because they serve different business purposes and therefore their semantics are completely different.
Basscss does not have any of this. Zero components. What it has is a set of simple and pre-defined CSS rules that could be used in any context where this rule is suitable to be applied.
Check this out.
.m0 {
margin: 0;
}
.p0 {
padding: 0;
}
Using narrow utility classes aimed to be highly reusable. Consider the following CSS code.
.success {
background-color: green;
color: white;
}
You can use .success
class only when both `green` background and white
text color are required. You would need to create a new class with a different name when only one rule of these two is required. Basscss confronts the semantic CSS approach.
Instead of coming up with a class name and assigning properties for a specific semantic meaning
<style>
.panel {
margin: 0;
padding: 0;
}
</style>
<div class="panel">This is a panel</div>
you use multiple classes like m0
and p0
mentioned above to achieve the same effect.
<style>
.m0 {
margin: 0;
}
.p0 {
padding: 0;
}
</style>
<div class="m0 p0">This is a panel</div>
Basscss contains shorthands not only for padding and margin, but for typography, borders, positions, colors, etc.
It was a strange approach but it got its fans and its own name called "Atomic CSS" inspiring a lot of other frameworks. One of them was Tachyons which introduced pseudo-classes for :hover, :active, :focused.
In this example zero margin is applied only when an element is hovered.
<div class="ma0:hover">This is a panel</div>
Another framework was ACSS, now known as Atomizer which used even more complex syntax and required a build step.
<div class="M(0)">This is a panel</div>
At first sight it looks like an inline styling, but it is actually more than that. It is a composition tool giving us an ability to construct different small pieces of software to produce a complete solution. This is exactly what we are getting by using Basscss and other atomic CSS solutions.
To achieve high quality composition one needs to have pieces of software that are
Going back to the example of .success
class let's break it down into 2 classes
.bg-green {
background-color: green;
}
.color-white {
color: white;
}
By splitting the .success
class we are no longer tied to a certain semantic and we can reuse individual classes in completely different and unrelated to each other contexts combining them with other such classes.
Of course, Tailwind took inspiration from all of the libraries mentioned above. Composition is the core concept in Tailwind and that’s how developers are expected to reason about it - by composing utility classes forming complex components. It focuses on being easy to use and very friendly to newcomers and developers who are not keen on frontend development.
What Tailwind got right is a good balance between API and functionality and a tooling which has nice defaults being highly-configurable at the same time. But is it actually a sustainable story?
There are a lot of critics of utility (functional) CSS. But I would mention only one, which is the strongest one, and that is mixing markup and styling results in having a messy class string in HTML.
<div class="bg-indigo-500 text-white px-4 py-2 rounded-md shadow-md hover:bg-indigo-600 transition duration-200 ease-in-out cursor-pointer flex items-center justify-center">
You might argue that it is a developer’s responsibility to keep it clean, but it is actually quite common to see this. Tailwind does not offer a way to clean the long class strings other than apply directive but even that is discouraged by Adam himself. Here is a quote.
I can say with absolute certainty that if I started Tailwind CSS over from scratch, there would be no `@apply`
The behavior is outrageously complicated, everyone struggles to build the right mental model of what it's supposed to do, and it encourages bad CSS architecture.
And it makes sense, because it defeats the whole purpose of writing utility CSS in the first place. Why even bother with it if you end up writing a separate semantic class name with a vendor specific keyword? You don’t need a library for that, just write a plain CSS.
Another way to fight it is to use a component based approach with a JavaScript library of your choice (React, Vue, etc.) and use something like tailwind-variants. This is also not a new concept, as it was popularized by styled-system, a Basscss author by the way. It works, and it works great despite introducing an imminent complexity.
But it still leaves critics with the question:
For now I will leave this question open. But I’m sure in the future we will see new approaches as CSS standards are constantly evolving.