One thing that has always struck me about Tailwind is that practically every argument its proponents use more or less boils down to “I never learnt CSS beyond a junior level”. It’s super common to hear Tailwind advocates say things like “Without Tailwind, we would just have one big disorganised CSS file that always grows uncontrollably and ends up with loads of obsolete stuff in it and !important everywhere! Tailwind is so much better!”.
CSS is a skill just like any other technical skill. If all you do is learn the bare minimum so you can bodge things until you get something that looks right, then your ambitions are going to outpace your ability to keep things organised very quickly.
It's worse than that; the common arguments for Tailwind literally derive from total ignorance of how CSS is made to work, and a disposal of guidelines that developers would worship in any other context (i.e. Don't Repeat Yourself).
It's really frustrating to be talking with someone about Tailwind and CSS, and realize that not only do they not know what "cascading" means, they never even considered the concept might be useful in the context of a stylesheet.
Tailwind, JS-in-CSS, and the like have become popular because they work well with the modern corporate UX workflow. A Figma component has a certain set of styles, you apply those same styles to the corresponding React component.
And none of this really violates DRY, your unit of reuse has shifted from a CSS class to a framework component. There's nothing precluding you from using an approach like DaisyUI if stock Tailwind has too much repetition for your taste.
> A Figma component has a certain set of styles, you apply those same styles to the corresponding React component.
This is what CSS classes were made for. Of all of the arguments in favor of Tailwind, this is the one that drives me battiest. Say what you will about CSS, but "give a name to a re-usable set of styles for a component" is pretty much as fundamental as you can get.
> And none of this really violates DRY, your unit of reuse has shifted from a CSS class to a framework component.
Sure, sure. except for the inline styles everywhere. And the fact that everything is literally being repeated all over the place. But other than that, no repetition!
> There's nothing precluding you from using an approach like DaisyUI if stock Tailwind has too much repetition for your taste.
That brings with it the problem of naming a thousand things in a consistent way that everyone on your team needs to understand and remember, otherwise you end up with tons of duplicated classes, parallel systems, and bike shedding. Have we, as an industry, not felt this pain often enough yet? Do we really need to keep banging our head against the wall to figure out it does hurt?
> Sure, sure. except for the inline styles everywhere.
There are no inline styles when using Tailwind. There are references to variables from the design system.
> And the fact that everything is literally being repeated all over the place.
If you find yourself repeating the same sequence of classes, it's time to create a component in your frontend framework if you use one, or a Tailwind utility class. And even if you just copy-paste the same class strings all over the codebase, transport compression will eliminate that pretty much entirely.
> That brings with it the problem of naming a thousand things in a consistent way that everyone on your team needs to understand and remember, otherwise you end up with tons of duplicated classes, parallel systems, and bike shedding. Have we, as an industry, not felt this pain often enough yet? Do we really need to keep banging our head against the wall to figure out it does hurt?
Of course. It's obviously better to have 10,000 different names that are all loosely, but not exactly the same as the CSS property they're trying to represent.
It undoubtedly is! I'd much rather learn 10,000 different names that follow a clear naming scheme and stay consistent between different projects and teams, than 1,000 different names that aren't guaranteed to have clear names or any consistency (even inside a single team).
But I'd also like to push back on the "10,000 different names" - the overwhelming majority of those names are merely variations of the value they assign, so using any class teaches you dozens to hundreds of those 10,000 names. So realistically, the comparison is closer to "1,000 project-specific and potentially inconsistent names" vs. "1,000 consistent names valid in any project using TW".
Tailwind doesn't solve technical problems really, it solves social ones. In a perfect world we all write vanilla CSS. But, in my experience, it becomes extremely messy and hard to reason about in huge codebases with lots of developers. Which sucks but isn't surprising to me.
Additionally, I do not think, that copy pasting a CSS class name everywhere is a realistic sane use-case. Usually, one would render some template and that template lives only in one place in some file, not all over the codebase. If we go smaller than a template, to use jinja language, we have macros as reusable parts, also not having them all over the codebase. It rings like a gigantic strawman to me.
Premature optimisation doesn’t even fully express how absolutely ridiculously futile it is to try and make your website faster by having fewer CSS selectors.
It’s like my grandparents worrying about immediately switching off their LED ceiling lamps when they leave a room - meant well, but utterly meaningless.
If you're using components, it's the same as Tailwind, just put your CSS module files next to the component, or use compile time CSS in TS frameworks like PandaCSS to have them in the code itself. For shared conventions that is the purview of the design system and you'd have CSS tokens for various colors etc. Anything you can do in Tailwind you can of course do in CSS modules because it's CSS at the end of the day.
I for one do not understand what is so difficult about making a team internal decision about how some "component" (here in quotes, as I am actually thinking of an HTML subtree with specific purpose somewhere on an HTML page) is going to be named, and then give it that name as CSS class. Are people never talking with each other? Are people unable to grep a code base, before making up a new name? And how many similar but not same purpose things do you have on your pages, that this becomes a serious problem? Or is it just a discipline problem? People can name hundreds of useless OOP abstraction classes, but cannot be bothered to think of a good name for a "component" on a web page?
I mean, come on, there is usually tons of context and team internal language for the new thing to build and to talk about it, distinguishing it from the old thing that was already built.
And if that's too hard, then allow the design department to name the things they design and notify them about any clashes. They must have a design language anyway.
Again, this isn't really about difficulty—you can solve problems of arbitrary complexity by establishing a process, guidelines, rules, and documentation. But unless your goal is maximising the number of meetings you need to communicate arbitrary naming conventions, having a framework that takes these decisions from you is an efficiency boost. There will always be new invariants, combinations, or elements to style.
Say you have a .button class for clickable button elements. One day a junior engineer realises they need two of them next to each other, while one is more important. Predictably, as they don't want to bother one of the seniors with this, they are going to introduce a .secondary variant. A few days later, someone else gets tasked with introducing a variant prop for <div class="card">, so the upsell banner can be styled differently easily. "Oh!", they think, "Neat! there's a secondary class that sets all the same props I need!"—and just like that, coupling was introduced.
Sure, this is a contrived example. The junior could have scoped the class to buttons; or added an explanatory comment; or written a note to the team; or asked a senior; someone could have seen it in code review; or a heap of other mitigations. But all of these happen to fail sometimes, and compound over time. This isn't even really about CSS, but entropy at the end.
So to me, this is the benefit Tailwind brings to the table: By providing a styling language that doesn't require making up rules as you go, that scales to arbitrary project sizes, and most importantly doesn't need additional communication, you get optimized, side-effect free CSS that you will immediately be productive in, even as a new joiner or when you return after a long time.
> but "give a name to a re-usable set of styles for a component" is pretty much as fundamental as you can get.
Yes. And as 30 years of CSS show, it's not enough.
> Sure, sure. except for the inline styles everywhere. And the fact that everything is literally being repeated all over the place.
It's not repeated all over the place, because in your codebase you have a single place where component A is defined. A single place where component B is defined etc.
I don't see you complaining about having to repeat the same CSS properties (padding, margin, display etc. + responsive styles + hover/disabled etc.) for half of the components when writing vanilla classes.
There are a bunch of differences between Figma styles and CSS styles that prevent you from creating a 1:1 mapping: typography inheritance, spacing rules, and variant specificity to name a few.
Like yes, CSS by itself is extremely powerful, but I see no reason why you should feel beholden to use all of its features simply because they're there.
> Sure, sure. except for the inline styles everywhere. And the fact that everything is literally being repeated all over the place. But other than that, no repetition!
Well, instead of repeating inline class names everywhere, you end up with CSS properties repeated everywhere. Not really seeing the difference.
> Well, instead of repeating inline class names everywhere, you end up with CSS properties repeated everywhere. Not really seeing the difference.
Erm...what now? That's so off-the-wall that I can't even wrap my head around your meaning.
Are you trying to argue that because, say, a conventional CSS file has "border:1px" in multiple places, this is somehow equivalent to the Tailwind approach of making a "b1p" class that captures the same thing [1], and plastering it across your templates?
Because a non-abusive application of CSS would actually just put that border property in a semantic class like ".widget" or something, and sure, you'd have multiple "border:1px" declarations across all of your CSS files, but that's irrelevant, because you're not trying to reconstitute every style inline from pseudo-properties.
[1] I am making this example up for illustrative purposes.
Yes, that's exactly what I'm saying. You don't end up needing a semantic class like .widget since you likely already have a Widget component in your codebase. Essentially:
In any real application you will have far fewer semantic class names than combinations of style properties. Working with concepts is vastly easier than trying to remember the specific property differences between concept A and concept B.
Obviously, a real application will have more than one css property. Also, your widgets will share styles, usually in a fairly obvious hierarchical way. And your designers will want them all to be consistent.
In this world, it’s far easier to remember that a widget is “.widget”, and that “.rounded-widget” is for the round version of that”, than it is to remember that the former concept is “.b1p .m5 .ib .xyz .pdq .foo” while the latter is “.b1p .m5 .p2 .br10 .xyz .bar”
The common arguments against Tailwind usually derive from total ignorance of working with CSS on large scale projects with many team members.
And when this is pointed out you’ll usually get replies that just hand wave it away as not a problem, as if things like BEM were invented for no reason.
> Sure it's possible, but is it possible for everyone on your team? Including the new hire, the interns, or the now-vibecoding managers?
Why aren't we asking this about any of the things that are actually hard? Like any programming language, or databases, or caching... CSS is the easiest part of the web stack.
> Why aren't we asking this about any of the things that are actually hard?
We do. That's what countless abstraction layers, linters, frameworks, style guides, and CI checks are for.
> CSS is the easiest part of the web stack.
…and because programmers keep thinking that, they stay ignorant about CSS and structuring the styles properly - leading to the problems I described above.
And the cascading thing is a nightmare even after years.
Whenever i have written CSS/TailwindCSS which was unproblematic to extend it was when i literally switch thinking to use least amount of properties and let the page flow.
Whenever i see tons of css i know it’s brittle and will cause hours of wasted time down the line to fix something which already should have been fixed.
DRY can be implemented using tailwind if you know how to. You can abuse tailwind and have no structure which I've seen even seniors do.
I've worked with CSS since 2001. Understood the CSS rendering engine in Mozilla like the matrix and written an absolute ton of cascading CSS using various methods and frameworks. All my stuff is now tailwind and it's pure bliss.
I'm fine with just the "cascading styles" part of CSS. The thing is it's also sizing and placement of elements in the webpage. Sometimes that's easy, other times there are 10 different ways to accomplish something that all feel hacky.
The more experienced Tailwind proponents probably have better things to do than get dragged into yet another online flamewar :) I've done tons of CSS since the 90s before looking into Tailwind. After it clicked, I've mostly tried to avoid raw CSS. In a sense, you exchange one mess for another. Personally, I'd rather deal with a localized class soup than trying to make sense of overlapping, often contradictory, cascades of styles across multiple files. Both can be implemented cleanly, but I'd much rather clean up a Tailwind mess than a CSS one. And I find the development process much more enjoyable overall.
> Personally, I'd rather deal with a localized class soup than trying to make sense of overlapping, often contradictory, cascades of styles across multiple files.
That seems like a false dichotomy. I'm a huge fan of locality (both in software engineering and in physis) but you can also "localize" your styles by scoping them appropriately. (Modern frontend frameworks typically do that automatically for you at the component level.) There is no need to use Tailwind for that.
You're misunderstanding me. I never said you should build a framework. I said frontend frameworks already provide style locality out of the box, so there is no need to introduce an additional framework (Tailwind) for that.
You aren't wrong, but the _overwhelming_ majority of "full stack" devs I've worked with only know CSS at the most basic level and have little interest in learning it in depth. I myself have been programming for more than 20 years, doing web dev for almost 15, and I can't find the motivation to learn it well. There are too many technical skills to keep up with and CSS is pretty low down on my priority list. I would prefer to rely on specialists who are experts but companies aren't willing to hire dedicated front end devs.
This is where I'm at. React makes sense to me in ways that plain CSS doesn't. I've learned about 15 programming languages by now, each time out of necessity, but CSS isn't one of them.
Isn't Tailwind easy to understand when you look at the codebase, rather than putting in more effort to learn a pure CSS codebase? Isn't that part of the argument of Tailwind being easier to scale?
What exactly has changed about Tailwind in, like, years? There are a few more properties for new CSS features, a few convenience features (like size-x instead of w-x h-x for the same values of x), but other than that? If you've grown accustomed to the utility classes eight years ago, then disappeared under a rock until today, you should be able to continue working in an unrelated, Tailwind-using project immediately.
I'm a big hater of Tailwind but also know that most CSS out there is an absolutely clusterf of outdated rules and !important wars. There's no winning when some dude jumps into the codebase and fixes a bug by adding margin-right to "p"
CSS linters never really picked up steam and even with them, what's lintable is quite limited.
I think there is a wide spectrum of "wrapping SQL", and very likely not because someone doesn't know SQL well. Depending on the use case, it can be just the right solution or overkill.
Tailwind, on the other hand, attempts to address a different set of problems, but I am not getting into that here -- other comments have summarized it well.
Do you have an actual list of arguments with the steps you take to boil them down to ignorance?
CSS is a design system, as like any system it can be poorly designed. Poorly designed systems require more effort to operate, and you can even call that "skills", but that just ignores the core issue of comparing design of those systems
"beyond a junior level" -- I doubt this will change your mind, but this post is from the author of Tachyons, a "pre-Tailwinds" competitor that didn't get the same traction:
And the tldr is that he downloaded and read the CSS for several major websites at the time (post is from 2016) and they were all hodge-podge of terribleness.
Maybe all the devs writing that CSS were junior, but imo it's more than CSS just doesn't have the abstractions to match the level of OCD/bespokeness that designers spec into every Figma -- move this box by _this_ much / _that_ much / etc.
Your comment is getting downvotes, not necessarily because you are wrong, but 1) CSS is indeed hard, complex and often confusing, which is partly why Tailwind exists in the first place 2) your comment points out some inconvenient facts, and people don't like that
Personally, I'm not sure from my own dives into it that I'd still insist on bare CSS in a professional codebase any more than I'd insist on plain DOM manipulation. And I do at least see Tailwind classes as being a little less of a DSL than other, similar tools. But while I'm not going to be a purist about it at a workplace, I both agree with you and have noticed a layer even beyond your point: that overreliance on these things leads to not learning HTML beyond a junior level.
It gets really easy to lean on class-based CSS and use a `<div>` for everything instead of ever learning what a semantic element is.
And that contributes to other bad habits, like writing a bunch of JavaScript to define behavior that could just be natively handled by your browser.
A weird personal irony is that because no employer has ever asked me to directly write CSS, what's actually made me better at CSS is JavaScript -- namely that my understanding of selector logic has improved a lot after picking up Web scraping.
I should probably note a detail I left out here: I myself care a lot about standards, and simply am stating that I wouldn't push teams around me to suddenly drop Tailwind even if I personally would rather not have to rely on things like it everywhere. Less that my opinion goes away and more that I don't presume it's the only valid option at scale.
But in my personal projects, I myself have just stopped using libraries entirely for styling.
CSS is a skill just like any other technical skill. If all you do is learn the bare minimum so you can bodge things until you get something that looks right, then your ambitions are going to outpace your ability to keep things organised very quickly.