No doubt is Tailwind a useful tool, especially for prototyping, but ultimately I feel as if it promotes terrible developer practices with flimsy, half-baked, ideologies powering its design. Ultimately I am not here to tell you that you're wrong for using TailwindCSS, use whatever tools make your life easier. But I care a lot about the tiny optimizations one can make to build better styles for the web, and here are my findings. NOTE: This is more of a ramble than anything else.
Adam Wathan's (in)Famous Blog Article
Adam Wathan wrote an article (that I just need to rant about for just a moment) titled CSS Utility Classes and "Separation of Concerns", and before even clicking the article itself, on the list of articles, Adam describes the article as Why “separation of concerns” is the wrong way to think about CSS and why presentational classes scale better than semantic classes. I strongly disagree that separation of concerns is the wrong way to think about CSS. CSS itself is a separation of concerns, but we will get more into that in a bit. CSS itself separates styles from the markup (for good reasons we will get into after I talk about this article).
Adam starts the article with how he was transitioning from semantic CSS to more "functional" CSS. Writing that the way he likes writing CSS can "evoke a pretty visceral reaction" from many developers, linking to a Tweet that has since been deleted. However, thanks to the Wayback Machine, I have since found the original post, talking about Tachyons, a functional CSS framework in the same-ish vein as Tailwind.
I do not agree that it is the "worst web dev idea of all time", that title goes to JSX for me.
Adam's Thoughts on Semantic CSS
I strongly agree that semantic CSS can be a pain in the ass. However, Adam's understanding of semantic CSS is a bit flawed, providing the worst example of "non-semantic" CSS I have ever seen. Based on how he described semantic CSS, it is understandable how he made that example that we will get into later. The idea is that your HTML should only contain information about your content, and all of your styling decisions should be made in your CSS. I see what he means, and his statement isn't "wrong" per-se, but he then provides this example HTML snippet for "non-semantic" CSS.
Not only is this perfectly semantic (depending on the context), but he uses this example for "semantic" CSS.
This is where when I first discovered Tailwind, I brushed it off as a nonsensical project by an idiot. I have since changed my mind on how intelligent Adam Wathan is, but this is still one of, if not the worst, CSS example I have ever seen, especially when considering semantics.
To describe why it is so bad, let's talk about semantics in CSS. In reality, HTML should only contain your content, and the class names it needs to style said content. Taking Adam's original description, I tweaked it a bit to fit more accurately with real semantic CSS: The idea is that your HTML should only contain your content and content-related attributes, and all of your styling decisions should be made in your CSS. Content-related attributes are things like class names, data attributes, ARIA, script and media sources, etc..
There are five things to semantic CSS, and the example of "semantic" CSS above breaks a few key things.
- Leverages semantic HTML to enhance the design (not applicable).
- Class names are meaningful and accurate to what the markup is, or needs to be.
- Class names should be repeatable.
- Never use IDs or tag names directly outside of CSS resets or where absolutely required (not applicable).
- Classes themselves should follow the cascade (not applicable).
The two things about class names themselves are very broken, whereas the original one follows the semantics perfectly. Yes, this does mean that Tailwind itself is a semantic CSS framework. The difference between component frameworks (which include custom made ones) and functional/atomic frameworks isn't semantics, but how those semantics are applied.
The Rest of the Article
There are many things I hate about Adam Wathan's article, especially how he writes his CSS. It is absolutely no wonder how he got into functional CSS. It does work better if you write CSS as bad as he did in 2017. But this article is about Tailwind, and not Adam's CSS skills, so let's talk about my main pain point with Tailwind.
Tailwind is Bloated
Wait wait wait Theo... before you comment on how Tailwind doesn't insert unused classes, I am not talking about the class names. What I am saying is that Tailwind itself bloats projects, and causes bloat. Much more so than component-based CSS. Now, I am going to provide some context to this section real fast. This is one example, and may not be the best example. I made two HTML files, one with components, one with pure Tailwind classes (grabbed straight from the utilities layer). The reason I didn't take the original CSS calculations is because I ignored the reset for both projects, and I wanted to take this a step further here in a moment.
I took two HTML files, one being component-driven, the other based on Tailwind's syntax.
For the CSS side, I first wanted to try the variables Tailwind includes, and copied them over to my style sheet.
This does NOT include any optimizations you can directly make to your component CSS files, which is important for here in a moment.
I then wrote a simple Python script to calculate the difference in sizes between component HTML and CSS and the Tailwind HTML and CSS.
With ZERO optimizations to the hand-written components, using Tailwind's own compilation methods, the Tailwind example is ~12% larger in bytes, and 20% more lines of code overall.
Now, with the original CSS file I wrote for the components, I had some magic numbers, and I thought for fun I would share how much bigger Tailwind is for small styles like this.
The HTML is no different from last time, so running these numbers Tailwind is over 45% larger. If we took into account the reset, almost 140% larger than this small CSS file. These numbers, while taken with a grain of salt, is a perfect reason not to use Tailwind.
Some Final Notes
Tailwind CSS isn't the worst thing in the world, and many of the other opinions I have on it are just that, opinions. I had a hunch Tailwind was worse than writing component CSS, and I hated Adam's reasoning. But ultimately this article was just more of a rant about my findings in a Python script I wrote, more so than an expose on why Tailwind sucks. Just why it's not the best. Bytes to bytes, Tailwind is worse, and gets worse with more components and complexity, but that isn't a major problem.
Ultimately this was just for fun, and to talk a little bit about why Tailwind isn't the best, but nor it is the worst.