I've seen this post flung around like it has any valid points about TailwindCss. https://dev.to/brianboyko/tailwindcss-adds-complexity-does-nothing-3hpn
I even had one of my colleagues post this saying he's worried about not being able to help frontend with styles because he doesn't like Tailwind.
So here I'll address all the points Brian made, with actual examples and a bit of logic, and as few opinions as possible.
But first let me address a few general points:
There are lots of posts like Brians, mostly saying that they don't "Like" it and it's their own "opinion", but then going down the road of insulting people for "liking" it or having a different "opinion" to theirs. Or they wrote a post a while back with most of the issues addressed by the team. Some of the posts update their answers, but most don't. Tailwind is still an evolving project. The four people behind it usually have the same problems and not enough time to solve them, but they typically address these points over time.
I sum these posts up like this:
- It's OK not to like it
- most of the points they make are their opinion and usually without sound logic.
- They throw "best practices" and other magical words around like it makes their arguments/points valid. Most "best practices" evolve. Sometimes "best practices" become "bad practices". So it doesn't make anything valid. It's all based on context and situation
- The ones I've read made "straw man" arguments and usually contradict themselves in the same post. I might be wrong, but I'm yet to find any post which addresses some actual problems with Tailwind.
- If you're writing static HTML without any js framework, some of the points are valid. But then they argue that Tailwind is suitable for small projects, but not enterprise. This statement contradicts itself. If you're writing a large scale app without using a component framework, you have more significant issues than using Tailwind, and maybe Tailwind is not a good fit for you.
Side note
I've written pure CSS. I've written a component library using SASS and BEM, so don't tell me that I should learn CSS or SCSS. I know them. I've used them.
This is just inline styles with extra steps.
This statement is wrong on so many levels, and he even contradicts himself in the same post when he writes a "solution" in the It's hard to read
part, which is not possible to solve with inline styles
.
So to clarify, no, it's not like inline styles and if you think that, maybe you don't understand the power tailwind gives you.
He gives an example:
<div class="flex">foo</div>
has the same exact effect as writing <div style="display: flex;">foo</div>
Then he discards the whole framework based on this contrived strawman argument. Because anything you can argue against inline styles is the same argument, you can raise against Tailwind.
Well, it's simply not true;
Sure you could write style="display: flex;"
but then how you make it responsive class="mx:flex"
the short answer is you can't put media queries in inline styles and not just that tailwind abstracts away from a lot of complex classes you would have to write.
Also, Tailwind is utility CSS CLASSES which means you get the full benefits of CSS, cascading, auto prefixing (with build tools), specificity and so forth.
What he does here is:
- Grabs a contrived strawman example
- Dismisses the whole framework because of that
- Then goes on a journey to try and write his own utility framework, but "better" with 'blackjack and stuff'.
I'm not making this up. He is writing a "better" utility framework!!!
It's WET, not DRY.
First of DRY is not as good as people claim it to be. Especially in the frontend, especially with CSS. DRY means tightly coupled.
I tend to write wet components. And only combine them when they seem to keep a consistent API. This, turns out, is a real lifesaver in quite a few cases, as usually they evolved into quite different components, and separating them would become a pain in the butt real quick.
He again raises a straw man argument. ANY MAJOR BRAND STYLE CHANGE WILL REQUIRE WORK. Like it's only applicable to Tailwind...
I don't know what he uses to write his HTML. In the comments, he says he works with React/Vue. I don't understand what he imagines people write their HTML like.
If you're working on anything significant, you will have a component library, and you should be writing code like this:
<BrandButton>Click me</BrandButton>
And not like this:
<button class="lots of tailwind classes here" >
Click me
</button>
Unless you're working with HTML only and have no way of writing components, then sure, his points are valid.
Stupid decisions will require a stupid amount of work.
So basically, he argues that when you only want to replace the buttons, you will have to find ALL the places where buttons were written and replace ALL those classes over millions of lines of code. As you see with an actual example of production-level code will be as simple as changing that one component.
He mentions that you will write bg-blue-500
instead of bg-primary-500
, sure if you're braindead and don't have even the slightest idea of how to write maintainable utility classes. Even if you write bg-blue-500
, which you agreed is the primary
colour.
It's easy to mass search and replace -blue-
with -primary-
or any other colour. But please, for your own sake, use branded/meaningful names primary
brand
accent
danger
are some good examples for colours. You can apply this to other classes.
He mentions that there are more changes when doing a redesign. If you write your components, the right way would be as simple as changing some Brand<Components>
. This is as much work as changing the CSS classes.
So again, a strawman argument that is easy to argue. But with any app which uses a framework that supports components. Those points are invalid.
HTML should only concern itself with the structure of your page, not the styling of the page.
Hello, 1990 called, and it wants its best practices back.
He writes:
In other words, your HTML (structure syntax) shouldn't have information about what the styles should be, it should only contain information about the structure of the page.
Sure if you have to write HTML without a framework that supports component
And the answer to that is STYLE COMPONENTS. Seriously it's like he's writing some mythical HTML that doesn't have logic and styling in it.
It's like he imagines that production level apps are writing html like:
Straw man:
<div class="card">
<h3 class="card__title">Straw man 1</h3>
<p class="card__body">We all write our code like this?</p>
</div>
<div class="card">
<h3 class="card__title">Straw man 2</h3>
<p class="card__body">Don't we?</p>
</div>
Actual production code:
<Point v-for="point in points"
:key="point.id"
v-bind="point"
/>
where <Point>
is a COMPONENT:
<template>
<div class="rounded-xl border border-brand-400 bg-white">
<h3 class="text-xl text-brand-400 font-title">
{{ title }}
<h3>
<p class="mt-4 text-brand-200">{{ description }}</p>
<div>
</template>
These points are somewhat strange, if not just plain crazy, or just the usual strawman arguments.
Which brings us to:
It's hard to read
This point is an OPINION, not a fact.
Here's the opposite opinion.
Here's an actual example of production level code:
<PageNew v-bind="page">
<ConfirmationAlert
v-if="shouldShowConfirmBookingCard"
:confirm-booking-path="confirmBookingPath"
:propose-changes-path="proposeChangesPath"
class="mb-2"
/>
<Tabs v-if="stateIs(STATES.IDLE)">
<DetailsTab v-bind="TABS.OVERVIEW">
<Overview />
</DetailsTab>
<DetailsTab v-bind="TABS.MESSAGES">
<Messages />
</DetailsTab>
<DetailsTab v-bind="TABS.ATTACHMENTS">
<Attachments />
</DetailsTab>
<DetailsTab v-bind="TABS.CHANGE_LOG">
<ChangeLog />
</DetailsTab>
</Tabs>
<ServerErrorCard v-if="stateIs(STATES.ERROR)"
@retry="fetchBookingOverview" />
<LoadingCard v-if="stateIs(STATES.LOADING)" />
</PageNew>
If you know how to use components, this is easy to achieve. And as you can see, there is ONE utility class in this high-level component.
OK, but what if you go deeper. Here's the <Overview>
component:
<div>
<CargoSummary v-bind="bookingData" />
<div class="flex space-x-2 mt-2">
<BookingDetails class="w-1/3" v-bind="bookingData" />
<SectionCard class="w-2/3" title="Ports & Dates">
<PortsReview v-if="portsAndDates" v-bind="portsAndDates" />
</SectionCard>
</div>
<PackingListOverview
v-if="!bookingData.isBulk"
:packing-list="packingList"
/>
</div>
Again only simple layout classes here. Which if you understand Tailwind, it is super easy to read and visualize.
Ok, but what if we go deeper? Here's the <SectionCard>
:
<div class="pt-8 pb-4 bg-white rounded-lg overflow-hidden shadow">
<div
class="px-6 pb-4 border-b flex items-baseline"
:class="{
'border-transparent': !border,
'border-brand-200': border,
}"
>
<div class="flex-1">
<Title>{{ title }}</Title>
<p v-if="subTitle" class="mt-2 text-sm leading-4">
{{ subTitle }}
</p>
</div>
<div v-if="$slots.actions" class="flex-shrink-0">
<slot name="actions" />
</div>
</div>
<div :class="{ 'px-6': padding }">
<slot />
</div>
</div>
That's full of Tailwind, and for me, this is beautiful.
With a bit of mastery of Tailwind, which has great documentation, or the tailwind plugin, which shows what a class does on hover:
This code is trivial to read and see how the styles are affected by the props. And this is my opinion.
Imagine having the same component written like this:
<div class="section-card">
<div
class="section-card__head"
:class="{
'section-card__head--bordered': border, // you now have to be aware that without this modifier class the border is transparent
}"
>
<div class="section-card__head__title"> // what is a better BEM name here?
<Title>{{ title }}</Title>
<p v-if="subTitle" class="section-card__subtitle">
{{ subTitle }}
</p>
</div>
<div v-if="$slots.actions" class="section-card__actions">
<slot name="actions" />
</div>
</div>
<div :class="{ 'section-card__body--padded': padding }">
<slot />
</div>
</div>
Suddenly you have to come with names for everything.
To understand what is happening, you have to keep switching to the CSS. I don't know Rick, this whole it's easier to read BEM or some classes you've made up
seems a bit contrived.
Naming is one of the more challenging problems in programming.
Tailwind has an unambiguous syntax with superb documentation, which means the naming problem mostly goes away.
And granted, this is still hard to read. But let me tell you.
I can catch VISUAL bugs just by READING the pull request.
I could never do this before. Using BEM or any other methodology.
Again this is my personal opinion/experience. So I won't argue it's not hard to read.
But using Components, you have the context of what the classes do, and only your low-level components should have that many classes in them.
And those components are complex whatever you use CSS/SCSS/tailwind.
It's localized complexity.
Whether you use CSS and class names and "simple" HTML, or you use styled-components.
Where you put the complexity is up to you.
But let me ask you which is easier to parse?
:class="{ 'section-card__body--padded': padding }"
or
:class="{ 'px-6': padding }"
especially when you can hover over the class and see this?:
Even without the plugin, you can read these classes and understand them.
If you know tailwinds consistent naming p = padding
x = means x-axis (left/right)
6 = means 1.5 rem
and it means this everywhere, with a few exceptions for the spacing.
These points are just an opinion.
But I'd rather learn something that has exceptionally well-documented API. Rather than writing inline styles
or writing my own utilities
or BEM.
He then argues:
"const h = 10" instead of "const height = 10"
Tailwind has SIX abbreviations, SOME modifiers and FIVE responsive design prefixes.
ABBREVIATIONS:
m - margin
p - padding
w - width
h - height
z - z-index
bg - background
MODIFIERS:
full - 100%
screen - 100 (vh or vw)
x - x axis, left/right
y - y axis, top/bottom
t - top
r - right
b - bottom
l - left
I think it's fair to say it's not hard to memorize these abbreviations. Most of these are so commonly used that they deserve their abbreviations.
So again, we have a strawman argument against a minor part of Tailwind, which is more helpful than burdensome. We all use a few Abbreviations here and there.
But remember the team is working. They have the same issues, and they will find a way to fix them. So this:
<div
class="w-16 h-16 rounded text-white bg-black py-1 px-2 m-1 text-sm md:w-32 md:h-32 md:rounded-md md:text-base lg:w-48 lg:h-48 lg:rounded-lg lg:text-lg"
>
Yikes.
</div>
Might become this in the future:
<div
class="w-16 h-16 rounded text-white bg-black py-1 px-2 m-1 text-sm md:(w-32 h-32 rounded-md text-base) lg:(w-48 h-48 rounded-lg text-lg)"
>
Yikes.
</div>
And In a framework where it allows backticks, you can mitigate this now:
<div
:class="`
w-16 h-16 rounded text-white bg-black py-1 px-2 m-1 text-sm
md:w-32 md:h-32 md:rounded-md md:text-base
lg:w-48 lg:h-48 lg:rounded-lg lg:text-lg
`"
>
Yikes.
</div>
Again for some classes, you might want to write custom CSS. I'd argue against it. But it's up to you.
You lose a lot of the features built into standard CSS
At this point, I think he loses it a bit, as most of those features are available in tailwind documentation Hover, Focus, & Other States
I think this covers about 90% of use cases for those features.
And anything that requires something more complex goes into custom CSS. Remember it's still an option? And no, you don't need to use @apply
.
It solves a problem that doesn't exist.
Some points here are valid, but they are valid for any other framework, even for custom CSS.
At least with Tailwind, it's not super complex to align it with your design system. And in the case it "dies", it's possible to take the project and maintain it, which is just as hard/easy depending on your team for your custom CSS.
At least with Tailwind, you're standing on the shoulders of Giants.
The documentation is superb.
The base work is done.
It's showing no signs of stopping.
It's an open-source supported by developers who use it for their own complimentary paid products.
This looks like it has a lot more possibility of staying alive than some other frameworks out there.
They built a fantastic open-source framework and are making their products based on the open-source work.
You're being disrespectful to the people who like Tailwind.
Here he contradicts himself literally in the same point and the next.
He writes:
My thesis is not, as you seem to think, "I don't like Tailwind, and therefore YOU shouldn't like Tailwind either". That's a 12 year old's viewpoint of technology criticism.
AND LITERALLY THE NEXT SENTENCE:
He writes:
Rather my thesis is: "If you choose Tailwind for a mission-critical application, you will end up making your job harder, your application more brittle, and your team, in the long-term, will suffer."
ALL based on his opinion.
He made a lot of strawman arguments.
He jumped hoops to show you and me the errors of our ways.
All of this sounds like this:
"My opinion is absolute, and you will suffer for not honouring it. You are foolish in your ways. Only I see the true path forward".
But CSS has massive problems!
He just lost it completely here, and those were some bold claims when he provided no unopinionated arguments.
Every argument in his post was a straw man.
Those that were not, apply to any framework, even custom CSS.
He proclaims that he is right, and anyone and everyone who is using Tailwind is a braindead moron who "starts hammering in nails with the butt end of a loaded revolver (Tailwind)."
A few benefits of Tailwind that he conveniently missed out
- Tailwind JIT builds super fast and a super slim CSS file with only the utilities you need in a single global CSS file.
- The exceptional documentation
- The framework is evolving and making even the most complex points invalid as we speak
- It's super customizable. Anything and everything is documented and customizable
- Speed of development
- Being able to "SEE" the components just by reading the HTML
- Size of the final CSS file.
-- Edit 10th May 2021 --
- Constraining css to a specific set of predefined rules following a design system, and added UI consistency even if you don't have a design system. - Thanks to @akryum
Look, it's OK if you don't like it.
Sure Tailwind is not for everyone.
Sure it has it's issues.
But those issues are persistent everywhere.
And people are working out ways to fix them.
BUT do not assume everyone who uses it is a moron who "starts hammering in nails with the butt end of a loaded revolver (Tailwind)."
You, sir have only provided opinions and hung up a lot of straw men. And you dare to claim that your view is something more than that.
A lot of people use it every day and reap the benefits.
No extra complexity.
No extra obscurity.
No need to come up with complex BEM naming architectures.
Which you might not be able to reap, based on your context and/or circumstances. And it's OK don't use it. But do not string up strawmen and opinions to bring other people down just because you don't like it.
Thank you for reading. Have a nice day.