Utility-first CSS is exception-first CSS
It seems like there's an never-ending stream of people posting about how they do not like Tailwind CSS, and by extension, utility-first CSS.
I understand their dislike, because utility-first CSS is ugly and verbose, but it is currently the best way to write exception-first CSS.
What does exception-first mean?
Let's backtrack a bit.
Traditional CSS that takes advantage of the cascade is, at it's core, about setting out a set of carefully considered rules over the visual styling and layout of your website or app. Ideally you would have a sensible system and all your pages and components would follow a limited, but smartly chosen set of rules and you do not deviate from these rules except in the rarest of circumstances.
That's the ideal world, perhaps feasible once upon a time where the business people do not know web and gave almost free rein to designers, but nowadays it's only possible for personal sites.
In commercial settings, you are at the whim of clients, bosses, managers, marketing team etc. You create your carefully considered set of rules, and then someone comes to you and says they wants to create something that breaks those rules - a special full page ad, a neat animation that is currently trending, or a new component that HAS to look/work different for whatever reason.
This happens again and again, and in no time your carefully considered set of rules is riddled with exceptions, until it's more exceptions than rules.
And your CSS collapses under its own weight.
Utility-first CSS consider every rule an exception, and creates a system to manage those exceptions. The end results being the overhead is much higher than traditional rules-based design, but you would never be overwhelmed by exceptions.
This is why I call it exception-first CSS.
Even for personal sites, your "carefully considered set of rules" is usually in flux and grows and changes as your site grows and changes.
So you have to keep refactoring your rules until you have refactor fatigue, and the advantage of having a limit set of rules diminishes greatly.
Does that mean utility-first CSS is the only way to write CSS?
Not a panacea
Not quite, utility/exception-first CSS lets you sidestep code refactor, but that does not mean you do not follow a design system.
It also means that you lose the convenience of being able to relying on those rules, and have to manually assemble design tokens into the layout and design you want.
Top-tier web designers of the pre-Tailwind era usually have a set of battle-tested baseline styles that suited their design sense, and so are able to mostly avoid the endless refactor for a growing and changing site.
High barrier of entry
Utility-based CSS requires added layers of abstraction, build-steps and dependencies that makes web design inaccessible for the lay-person.
You lose that sense of fun and spontaneity when you can no longer whip up a site in a plain text editor, and can't make changes easily in the dev console.
And so, this ends my thoughts on utility-first CSS in general and Tailwind in particular.
I don't find it fun, it feels clunky and forced, but it is really the most sensible way to deal with exception-riddled web designs prevalent in the commercial world.
If I'm designing a website for a job, I would not hesitate to use Tailwind.
But when I'm designing my personal site, I'd rather avoid the overhead by keeping my design simple and logical.