Join the discussion
Write your take first — we'll ask for email only when you're ready to publish.
- Hacker News
- I've used a lot of tailwind professionally over the last few years and I agree with this article - it is spot on.
I never even use tailwind in my own stuff, even though I think that small devoper-led side-projects are where it is a good fit (and the reason for it's popularity).
by monkeyisland - I have the opposite experience regarding where it’s useful. In large teams , using an atomic css framework provides good guard rails and predictable behavior. I can confidently copy a marketing page or some random thing on the other side of the company and with very minimal tweaking, it will probably work. With normal CSS, the cascade is much more likely to cause subtle shifts in behavior over time as the main stylesheet is extended and modified.
To be clear, I like css and I find the cascade a great tool, but I also have first hand experienced the pain of too many chefs in the frontend styling kitchen and the havoc that seemingly innocent tweaks here or there can wreak on a site and I prefer tailwind for that reason.
by yurishimo - This is written from a point of view of somebody who never went through the progression of CSS to CSS preprocessors to component-based frontend libraries. Tailwind is an answer to all the problems that become apparent in CSS in that progression.by parasti
- I tried to use Tailwind in a hobby project couple years ago. I havn't updated my CSS skills since 2010 or 2015 -- I certainly missed grid layout and some other new features.
Quickly, I realized Tailwind is documented on top on CSS, no way around. This makes you keep in mind both.
No idea why is Tailwind even a thing.
by eugene3306 - CSS Modules are a better solution. They compile classnames into unique identifiers, so there's no need for BEM or SMACSS conventions:by efortis
- I disagree. I don't want to jump between two files constantly. With Tailwind I can stick to one file and never need to think about naming things.
- Show me one non-trivial project with classic, well-organized CSS usage and clean semantic HTML. It just never works out. There were attempts like BEM, which looks promising at first sight but is awkward at some points and only works if all devs strictly follow the convention. We all know how this usually works out. I once was that semantic HTML and css classes guy too, I completely changed my mind. In the end, we want to efficiently build a clean and shiny website. No real user looks into the (unminified) HTML source code to appreciate those awesome, sophisticated semantic CSS classes.by ckdot
- Saying "unless you use @apply" invalidates this article for me. Everyone knows that @apply only exists as an escape hatch, it is not supposed to be used, except for when it's necessary like for compatibility with libraries that declare their own classes that you need to override.
The most commonly repeated point in the article is "escape hatches bad" and I think that's completely absurd. Of course you want escape hatches, otherwise when you do hit an edgecase you get stuck with no solution. That's exactly what would force you to throw away that approach and pivot. Tailwind doesn't have that problem because it was designed to include escape hatches.
Users deciding to use those escape hatches instead of sticking to a design, isn't Tailwind's fault.
- It makes no sense for me that @apply is frowned upon. It's what makes Tailwind actually kinda usable for me. Without it, markup looks like line noise full of boilerplate that's hard to modify in a systematic way.
I think what Tailwind actually needs is more abstractions, not to discourage the use of the sole abstraction @apply
- What is funny with your article is that you talk about tradition, when actually these traditions are based on assumptions which are themselves based on beliefs like : "separation of structure and style are a good thing".
But this belief is only true if the language to describe the structure is html or js which creates not reusable pieces of style/structure.
But when you go for a different approach where everything is functions and strong types (ADT), like when you use haskell for exemple, this debate is over, because you handle EVERYTHING in your code, and stop fragmenting the truth into opaque and dissociated worlds (html, js, css, database, glue, docker, ...).
by tibastral2 - I don't recommend css. Css is BLOATED. And tailwind makes it a little less bloated, but it's still not strongly typed, and not very re-usable, especially in code.
But your approach is from the past man, really... .btn is not reusable among pages / projects / etc. => it's always different, and when you understand that specificity wars is the main problem of css, you will not want to use your idea again.
It LOOKS cool to have a <button class="btn"> inside your html. because it's more readable. But it's NOT explicit. You fragment truth into different pieces. and it makes it IMPOSSIBLE to test things in isolation.
One last thing. Using all the "last features" of css is just putting you in a place where you depend on the browser carriers to handle things for you when I prefer personnaly to rely on myself and my craft. But that's a personal one ;)
by tibastral2 - I think this is a protypical discussion in tech. I have seen it soo many times in different areas.
The purists ("that’s how things ought to be!") and the pragmatists ("well but it works well and people understand it seemingly").
by baxtr - We need to talk about two use-cases separately:
CSS for design systems is fine. You can define a .button[data-variant=”primary”]. It’s intuitive, performant, makes sense.
CSS for application code is terrible — specifically layout & typography. The different kinds of flex/grid layouts are tightly coupled to the dom structure. Tailwind is a great fit here:
When you remove layouting concerns and maybe typography. You actually get close to the separation of concerns that CSS was initially aiming for. HTML determines arrangement and css determines the design system (colors, borders, shadows etc...).<li class=”flex flex-col”> <div class=”font-medium”>Title</div> <div class=”text-sm”>Subtitle</div> </li>I havent seen this discussed a lot. The old Radix team had a short note: https://www.radix-ui.com/blog/themes-3#the-best-of-both-worl...
by SebastianKra - For a very long time now I've avoided anything other than 1 class per div with style overrides and written with modular rules and 1-2 degrees of separation between label and rules.
Something like
.title {
}@include type-heading; &.LARGE { @include font-size-large; } @include onMobile { ...something }This has the advantage of being naturally rule based and amazingly succinct to write and understand. Needless to say I'm an odd duck, since I almost never see css written this way.
(edit: I forgot how to format code on HN)
by interstice - As a 26+ year frontender, years ago I was against it on so many levels. Until I tried it.
Never looked back. Also, inheriting projects with someone else’s code is fine. Just a quick look at the central config and you’re good to go.
by grsmvg - 100% this. It looks terrible until you try it and it starts making so much sense.
Also works great with agent assisted development.
by ejoebstl - I felt the same way with JSX. Started using it and don't want to look back. Same with Tailwind.
- Tailwind is like Air Fryers in that way. I have been cooking for decades. I have a convection oven. Air Fryer is just an undersized version of one. But then you try one, and it turns out they are amazing.by TiredOfLife
- Totally agree. It does break the rules, but it feels so much faster than defining class names.
On simple projects I usually @apply tailwind styles to standard elements like headings, block quote, aside, nav etc. Then just use semantic html.
Looks good and takes so little effort.
- Tailwind looks bad on "paper". It violates a lot of "best practices". It is ugly. Yet in reality it works. It gets the job done. It is fast to work with.
Constraints are known to enhance creativity.
by arnejenssen - I was very much in the Tailwind camp, and simultaneously loved it for its local reasoning and disliked it for how its long class names messed up my components. It has always felt like a bolted-on hack to me but I couldn't argue with the benefits.
Turns out, CSS Modules comes with the same benefits while feeling much more like a natural extension to the web platform. The only thing I thoroughly miss is functions and directives, which hopefully will land in browsers through the mixins proposal in not too long of a time.
by herrkanin - I see you have a .button, cool! So did you load the entire context of your project into your mind, and calculate every possible iteration of kind, size, color etc this button may have? And once you did that, did you come up with a semantically correct naming scheme that is clear and will not succumb to the inevitable .button_checkout_special_page_cta_widget a particular page will end up requiring?
No? Neither did I. I stopped thinking about CSS entirely almost a decade ago. Thanks Tailwind.
by pixard - And did you remember to include the exact same Tailwind classes with every instance of your button in your project?by pupppet
- I know what you mean. But somehow that doesn't bother me. In fact it forces me to think about consistency of the design and often makes me think of a more general schema and simplifications in styling, or getting rid of something too specific/special.by zelphirkalt
- Yes.
you just add `checkout` class or `big` class to your button. or use `.checkout-page .button` to modify look/size of your whatever button on the checkout page if it's style is truly unique and not used anywhere else.
by megous - Don’t you need to keep more context in your mind if you use Tailwaind to make .button_checkout_special_page_cta_widget while staying somewhat consistent?
Could you give us a few examples with and without Tailwind, including CSS variable and compose in preprocessors?
- Yes. Bootstrap and all other CSS frameworks before Tailwind did it, too.
It's a matter of preference, but many times it's easier to have single classes so that all your buttons are consistent.
People should just use the tool they're more productive with.
by altern8 - You still have to remember what sizes or whatever to use for what to make it consistent, it’s just they get packed into the “class” attribute. It’s not uncommon to see very long class attribute lines with tailwind with all kinds of p-this and mx-that or whatever. I’ve also seen quite a lot of p-[whatever] tags, at which point all the consistency goes out the window.
So you end up wrapping the components (if you’re using react or something similar) so that you can centralise the styles and use a set of consistent components instead. And at that point it really doesn’t matter if you use tailwind, custom classes, per component css modules, style attributes, css-in-js, or what have you. At this point I prefer to drop the extra dependency and use per-component css files with css module imports. (Or when I do less custom styled UI’s, I prefer to use Mantine and use its attributes for layout and styling)
by dkersten - I feel like scoped css and component libraries fixed this issue. I don’t have a .button, I just have a <Button> that has all its css self contained.
And just a shared color definition file.
by Gigachad - It’s funny, as someone that’s been using CSS for decades I don’t really know how to respond because the scenario outlined here is not one I recognise. My button would be a <button>, so no, I wouldn’t have a .button class, it’s superfluous.
What I would have is:
- a global palette specified via CSS variables
- overrides for dark mode etc specified at the global level so I don’t have to worry about it at the component level
- CSS module files so I specifically don’t need to care for the context of my entire project, just the classes for my current component
Of course, you stopped thinking about CSS a decade ago so you don’t know about any of these improvements. Which is fine but it strikes me as a little strange to be so boastful of ignorance.
As someone who has barely touched Tailwind I’m genuinely curious: if you wanted, say, a consistent border color for use across your project how would you? Are you defining a class name in JS for use with $framework_name? And do you really style each component separately for dark mode? Repeating the same modifiers over and over?
by afavour