These are fairly complex use-cases that aren't needed for 99.9% of CSS people write. In most cases I'm throwing together a handful of components in a flex container or right-aligning some buttons or something.
And for that typical CSS usecase, I find Tailwind way better both for quickly iterating and for hopping into code someone else wrote. I love not having to bounce between and cross-reference 2 (or more!) files (HTML + CSS) for a description of a single layout.
I started using Tailwind at my job I started 2.5 years ago and after the learning curve of memorizing the commonly used class names I have yet to run into a situation where I wished we weren't using it. I also started adopting it in all my personal projects because it makes me so much faster at getting work done and the code is easier to maintain.
I really feel like people start with their conclusion that they don't like it because it's weird and foreign and then look for excuses to justify why they think it's bad.
> I really feel like people start with their conclusion that they don't like it because it's weird and foreign and then look for excuses to justify why they think it's bad.
At least from this article, I get the impression the author used tailwind for a bit and kept running into these issues where he had to go in and fix it manually in CSS. After enough of these, you get annoyed.
If they're typical things that you'd expect a library to solve, sure. If they're "I want my element to rotate in 3D" then most developers would think they're just working outside of the scope of the library.
Yes tailwind let's you reach through and apply some CSS directly. Almost like its an abstraction that exposes, or leaks, that which it attemps to abstract. A "leaky abstraction" if you will.
Honestly - I find this opinion misguided. It's like saying a for loop is a leaky abstraction over a while loop.
Which... is asinine. One is simply a redacted and simplified expression of the most common implementation of the other case.
Tailwind falls into the same bucket - in my opinion. Like most frameworks, it's not there to handle your niche and complex use-cases. It's there to provide bumpers that push you into a pit of success for common use cases.
When you need to do something that's not common - use the escape hatches that are built in. That's not leaking - that's giving you the flexibility to fall back to a custom implementation.
The goal just isn't "abstraction" from css. It's common-sense, local, and consistent styling for common cases. I can build most lego sets from single square blocks - but it's nice to have a bigger selection available. Does that mean I need to understand those bigger pieces to make sure they fit, don't have weird gaps, and line up? Absolutely. Does that mean I shouldn't use them? No, probably not. But it does mean that sometimes I still need single square blocks.
I think the opinion here comes from other compile-to-x languages.
Let’s look at typescript, or sass. There is (afaik) no construct in the underlying js or css that cannot be represented using them.
You could conceivably never learn javascript, learn typescript and basically be fine.
So when people say “leaky abstraction” they seem to be assuming that tailwind, which is a framework will allow you to represent every possible css output.
…which it can’t do, obviously, and was never intended to do.
All I’m pointing out is that the expectation that it could might not be quite so daft when viewed from the lens of “I expected tailwind to be a framework in the same way sass is” or perhaps “the same way this framework that compiles using sass is”.
It’s like if I was using vue, and found that the template language can’t express complex logic without writing js (h() expressions) and not using the template language at all.
It’s wrong to say it’s a leaky abstraction; but it’s maybe not completely asinine to say, it a bit rubbish that you have to do that as soon as you hit any non trivial use case…
> Like most frameworks, it's not there to handle your niche and complex use-cases. It's there to provide bumpers that push you into a pit of success for common use cases.
…but as you say. Quite so. Im just saying I can see the frustration people encounter when they have the naive expectation that those edge cases are rare enough they’ll never hit them, and then immediately run into them.
I guess I see it as the opinion of someone who hasn't used it, or doesn't really understand the value.
I don't love Tailwind, but I can understand the spot it's trying to fit in, and I value the things it's trying to offer (locality, consistency, sane guidelines).
I think the sweet spot for that value proposition is projects where the designs don't need to be pixel perfect or extra fancy - they just need to work, quickly. I've used it successfully several times in those cases. Not to mention personal projects where just having a decent template made that I can tweak is great.
I would probably not use it anywhere you have real UI constraints or concerns, and you care a lot about specific animations or exact pixel placement. I tend to reach for styled-components in those spots these days. Since it gives me a fair share of the same value proposition (locality, consistency) but removes the guidelines/bumpers.
They play pretty nicely together (with some constraints), though - again, use the different lego blocks where they make sense. Stop trying to treat everything like a tailwind shaped nail you have to beat in with just that hammer.
poor take - tailwind is not trying to abstract CSS away from you. Abstracting away CSS would be painful and pointless - theres no way a higher-level language could emerge that would give the user the same feature parity.
You can play this "leaky abstraction" game with almost any concept, without the ability to reach down an abstraction level you lose flexibility. Its not a smell to be slightly leaky.
Tailwind is honestly great for beginners since it "simplifies" CSS into short-hand classes. The people that know CSS don't want to learn new classnames when they can use CSS and that is a standard.
I'm personally scared of forgetting CSS if I use Tailwind extensively. I also don't like the aesthetic of all the classnames being bunched together, but Tailwind does have value.
Honestly I just don't see how it's possible to 'forget CSS' with Tailwind. I mean, the classes mostly map 1:1 to CSS properties.
As someone who has been writing CSS for approximately a billion years (actual number more like 13 years) I'm a fan of Tailwind and don't see how it's a 'beginner' thing at all. It solves real-world problems building web applications, and actually many of those problems only come up when you're building large, long-lived applications with many contributing developers which is precisely the kind of thing beginners aren't in charge of.
Tbh a lot of times when people say beginner they really mean “this is way easier than the way I’m used to, and that freaks me out because it means the old way is redundant, so I’ll claim this is for beginners”
By beginners, I meant people who know HTML and some CSS, but not enough to design a great UI. Tailwind allows them to add a few classnames and the page looks great. On the flip side, you have a developer who can design using CSS. Tailwind comes along and, although it’s great, you’re learning new classnames and now you’re no longer using web standard properties (CSS).
This makes no sense. Tailwind is just another way of writing CSS, it's not premade styles.
> Tailwind allows them to add a few classnames and the page looks great
How is this the case any more than "raw CSS allows them to add a few styles and the page looks great"? You can't just haphazardly throw styles onto the page and it'll magically look good cause it was made in Tailwind. You design the exact same way you would if you were writing raw CSS, it's just you're putting the styles in the HTML class tags instead of modifying the CSS directly.
A person who's bad at CSS is not gonna be any better with Tailwind.
> I don't see how tailwind makes it easy to design beautiful pages, not in an easier way than CSS.
If you copy the examples in the Tailwind docs it looks like your ripped off Stripe. If you copy the examples in the MDN css docs it looks like you ripped off a decade old govt site.
By that definition it would be hard to justify anything besides HTML, JS and CSS. That would also exclude TypeScript and every JS Framework there is on earth. That's hard to justify from every angle (development and business wise) imho.
That's not quite the definition they are positing. Many of the classes in Tailwind have near or actual 1:1 mappings to CSS, but with slightly different names or semantics. A better JS analogy might be something like Coffeescript; I remember avoiding it because it felt a bit superfluous and hence not worth the tax (of adding a tool).
With Tailwind, whatever the actual merits, the biggest points of traction (IMHO) are the frankly excellent example sites[1]. You can click through numerous examples, all load quickly and without ads, that give you numerous variations of components, layouts, and even full pages. You can spin up a vanilla HTML or React app and ship good looking pages very quickly, esp. if you are bad at design.
I use Tailwind for a SaaS app because of TailwindUI and I'm pretty happy with it. I also used the Marketing page examples to put together a website[1] pretty quickly.
When the app UI gets more complicated the need for design skills definitely creeps in. But, taking a step back, using a wireframing tool like Balsamiq, and having another look through the component catalog has gotten me pretty far. I'm happy with our ability to ship quickly.
Just an FYI, the logo on the site you posted gets deformed on mobile when there’s not enough space for it and the buttons on the right to live all on the same line.
I should clarify, I wasn't a beginner when I started using Tailwind. I already had frontend experience, it's just my current job already had started using Tailwind in all their webapps before I started.
I don't think Tailwind is the place to start learning CSS. Tailwind is just a more efficient way to write CSS, and you should be aware of what's going on under the hood. It doesn't mean if you're writing your CSS in Tailwind you're never gonna look at normal CSS. There's plenty of times when I'm iterating on a design and I'll hop into the "Styles" section of my console and directly edit the element.style{} section, writing normal CSS to mock something out before translating it back into Tailwind in my editor.
So I certainly haven't forgotten normal CSS names. Not to mention the Tailwind names generally match up pretty closely with the underlying CSS names. It's only minor translations to go between the two, and maybe a special case here or there. The documentation[1] is very good with a quick search can type CSS or Tailwind names into to find what you want, and it'll show both the Tailwind name and the CSS attributes/values it outputs so I tend to keep that open in a tab while I work.
For me Tailwind is sort of a shortcut to learning best practices. If I had to research and figure out best practices on my own it would take ages. Instead I can just see what Tailwind does. E.g. when to use em vs px. That kind of stuff.
I’m not sure why it’s limited to beginners. I’ve been writing CSS for 20+ years and found it tedious, error prone, difficult to manage, and irritating. Tailwind honestly made me enjoy doing web again.
It’s definitely not limited to beginners. Huge companies are using Tailwind in production. I prefer CSS-in-JS and haven’t faced enough issues to switch.
Have you ever had the 'pleasure' of maintaining someone else's non-trivial, non-framework CSS? I have, and it was no fun at all. For all the crap they get, frameworks allow for knowledge transfer across projects/teams/employers.
I think its possible to forget some of the exact names, but most of the Tailwind classes are just shorthands for the CSS styles. Furthermore, even if you develop in Tailwind, you still see the normal CSS style names when using browser tools.
If you decided to do a project in vanilla CSS, I'm sure the style names would come back very quickly.
I know CSS and have been using it for over two decades. I found that using Tailwind was like having a mental burden taken from me. I don't care about exact pixel values, most of the time, I just want a consistent UI with "some level of spacing". I don't want to do strange niche stuff 99% of the time. Tailwind's strength is the constraints and defaults it provides you.
> The people that know CSS don't want to learn new classnames when they can use CSS and that is a standard.
And then they end up with dozens (and in big project hundreds) of bespoke CSS class names that no one can remember or keep track of, and just add new ones to the ever expanding file ;)
I'm curious, if you're using CSS-in-JS already why not jump to tailwind? Its slightly more restrictive, but I've found the more opinionated style incredibly helpful.
What are the benefits you're getting from CSS-in-JS?
I use Mantine[0] which uses Emotion[1] for styling. I like keeping the CSS properties in a neat JSON object instead of a long string like Tailwind does. With the object approach, conditional styling is easier too. With Tailwind, you have to use cx or another package to do this and it makes the code a little hard to read.
Emotion isn't without it's flaws though. The company that created Emotion doesn't use it anymore because of runtime overhead[2] so Tailwind may be the future after all.
I used to sort of like CSS-in-JS, but on larger projects it also quickly devolves into "I know we have a design system, no idea what we have there, here are one-off CSS styles for this particular component"
Use CSS modules then. The largest CSS file in the largest application I'm working on is around 200 lines (I prefer splitting everything into small components — easier to test, easier to reuse).
I agree that the use cases shown are not representative of the vast majority of projects. After using Tailwind for almost two years, I find the biggest strengths are: a common set of naming conventions (don't underestimate how hard it is to name classes well and consistently across projects); bundling of commonly used features (autoprefixing, purging unused classes); and how well it works with component libraries. Beyond that, Tailwind is just CSS — unlike pre-compilers like SaaS and LESS that actually extend CSS.
Exactly. No matter what, this person decided before they even used tailwinds that it was going to be bad. They used their time with the tool to point out obscure cases so they could say "see, I was right, it leaks". They then try to tie together at the end with a "I'm not saying it was bad".
This type of drama or negative style of writing needs to stop. Be objective, there is good and bad everywhere.
> I love not having to bounce between and cross-reference 2 (or more!) files (HTML + CSS) for a description of a single layout.
Oh wow. Literally this is the exact argument I use for not using tailwind - not having my styling logic split between classes in my HTML and tailwind’s own files implementing the styles (which appears in DevTools and most other places).
Not saying either of us is right or wrong it’s just odd how different people perceive things.
Does your framework do CSS in it’s component files? If not, maybe that’s the problem?
No, I have HTML and CSS in the same component file. I prefer having styling in one place (the CSS inside the component file) rather than two (the HTML of the component and tailwinds’s own postcss files that implement the styles).
Standardised and clean CSS syntax. The benefits in that context are debatable, a component based frontend architecture is where it absolutely shines. If you end up using it in that context you won't need to ask this question, it quickly becomes clear that it's the optimal path.
What can't pure CSS do here and that Tailwind does ? The CSS syntax is already clean and standardized if you use it properly and don't name every little piece of interface. It is a genuine question, by the way...
> How does Tailwind require bouncing between multiple files?
You have styling split between the classes and the actual CSS tailwind implements, which every team I know that has used tailwind absolutely does have to look at.
I agree that ‘div soup’ is a problem - I’ve seen a lot of react code by new developers that resembles GWT generated DOMs. But ‘div soup’ has other problems too - way over complicated doms are hard to edit and debug - and the problem is better solved by learning CSS basics to avoid all the wrapper divs you see in React apps made by junior front end developers.
Most of the time I know the CSS already I have to convert it to tailwind - and devtools uses the same syntax so (as the article mentions) the abstraction leaks.
So just to be clear: your argument is that you like to cross reference multiple files before you know what is applied, when?
And for the record, tailwind was never meant to be used exclusively. Most arguments against it are centered around edge cases which are tiresome with tailwind... But they're usually pretty silly as you were never meant to abstain from using css if it makes sense.
And yes, that means you'll still have to check multiple files if something behaves differently then you'd expect, it's just less frequent then without a utility css framework
The other cool thing is that you can code up your design system in the tailwind config and never have to worry about devs not using the correct sizes/colours/etc.
Practically none. And any designer is prone to reuse the same spacings from project to project. So you bring the language file with you. Something like this :
One thing that has been an absolute deal breaker for me is adding variants for components.
Say I have a button component with different variants, these variants change styles across multiple elements in the component.
Using scss and BEM this is incredibly simple, add a parent class and I can modify nested elements easily. But using tailwind I have to make an mess of things to get this working or recreate the component.
I've looked at tailwind as an individual, but their pay-for-documentation model is absolutely bullshit. And it doesn't seem to be doing anything different from Bootstrap or 99% of the other CSS frameworks out there.
Also, it makes me sad to see people so eager to throw away separation of concerns :( Yes everything describing it is on one screen but now your HTML is filled up with hundreds of words of awful classnames and markup that should have been put elsewhere!
Yikers this comment sets the stage for a real bad game of phone tag! I think you're mistaking TailwindUI[0], the set of proprietary UI component cheat codes based on top of TailwindCSS, with TailwindCSS[1], the actual CSS library being discussed here.
I'd give the makers of Tailwind the benefit of the doubt here. TailwindUI was very much launched well after Tailwind CSS was popular, and they probably assumed you'd only find it after you'd kicked the Tailwind CSS tires a bit.
> Also, it makes me sad to see people so eager to throw away separation of concerns
I don’t think it has ever lived up to expectations, HTML+CSS in that way is simply broken. You can’t really write CSS without hard-coding the HTML structure, so you might as well do it in one file.
No, I think people just suck now. While you can't eliminate all structural concerns in CSS (think nesting selectors), sensible class naming and adhering to the structure of the medium (instead of fighting it by trying to directly translate a photoshop mockup or w/e), this is entirely possible.
But now you just have a single-use html+stylesheet, as I wrote. No separation of concern anywhere, and both html and css can only be written by knowing the other part.
Why is the stylesheet single use? The classes can be used anywhere, as they should be. Make components in the CSS and call them by their classname in HTML. You are building generic components here.
I don't see the issue with 'separate files', do people not use split view mode in their IDE?
> Why is the stylesheet single use? The classes can be used anywhere, as they should be. Make components in the CSS and call them by their classname in HTML. You are building generic components here.
The problem with reusing CSS comes, when the style you’ve previously created, is almost, but not exactly perfect for the current component. Changing it to better fit you current need risks breaking existing layouts, and so you are left with overriding it. But when you do that, you eventually end up with a lot of override classes just to change one or two things. So, what do you name these classes? If you name them for what they are intended for (ie. “semantically”), you are bound to end up with a lot of differently named classes, that all do the same or nearly the same thing, because it turns out that we commonly want to override the default styling in very similar ways. You end up with dozens of one-rule classes that all just set float to right or display to none. Alternatively, you name these overrides for what they do. This way, whenever you need to float something right, you just add the `float-right` class to the element. You can now eliminate all those redundant semantically names override classes. But if you go back to the classes you started with, it also turns out that those would have been a lot more reusable if they’d contained fewer rules to begin with. This makes sense, because more rules = more specific, and fewer rules means more general. At this point, I’m sure I don’t have to point out to you, that you’re well on your way to reinventing Tailwind.
But you aren't building a generic product. You are building something specific.
I'm my experience the _vast_ majority of CSS never gets reused. Sure if all you are building is marketing websites or landing pages then I suppose some generic "cards" or whatever will get you pretty far, but for anything even moderately more complex... no chance
Separation of concerns went out of the window a long time ago when frameworks (i.e. React) showed that it's better to combine business logic + markup into a neat encapsulated package.
Having a neatly encapsulated component that does everything is fine in most setups. Your main challenge will be not growing these components too big.
(( I really dislike Tailwind btw, mostly because I am just translating CSS into something else all the time which feels like a waste of mental effort; and the long lines of cryptic classnames is just bizarre to gain such a big popularity. I loathe it, it's a maintenance hell. I imagine all frontend devs liking this grew up using Bootstrap or something and mostly do small projects ))
> But that's kind of the point. Tailwind is a layer on top of CSS, but it doesn't actually hide any complexity in the layer below. You still need to know CSS.
This completely misses the point of Tailwind. The point is not to hide the complexity of CSS, but to provide access from the markup to enough of capabilities of CSS that you don't have to edit your stylesheets 95% of the time, when you alter the styling of a document.
When Tailwind does fall short because it doesn't provide the exact CSS feature that is needed to solve the problem, it still provides a template for how to solve the problem: Using one-rule utility classes, that are named for what they do, not for how they are meant to be used.
Maybe I'm going out of a limb here, but wasn't the whole point of CSS to not have to touch the markup when changing the styling? Not trying to talk Tailwind down, I have just missed a lot of the evolution of web design in the past 15 or so years.
I've never understood the point of separating markup from the design. I've seen CSS Zen Garden and... neat? But I don't get the point in real-world use. I've never had to redesign a UI in a way where I'd only change CSS and not also be moving around markup in the process. And once you're changing both of those things, there's the overhead of cross-referencing and keeping names and hierarchy in sync. At that point I don't know why I'd want the 2 separate.
The most magical moment for me when I started using Tailwind was realizing you can simply cut-and-paste an arbitrary block of HTML from one place to another and have it just render exactly as you'd expect. You don't have to additionally copy-paste a block of CSS, and then fudge around with the selectors because in the previous place it expected to be in some parent container or what have you.
The question of where to put the styles boils down to "do your content and style people work in completely separate teams?" For a newspaper, this is true. For someone who got their mate to set up their blog, this is true. Early days web was mostly like that. Not any more. If it's the same person doing it, put it in the same place. Separation will just be a hindrance.
That reminds me the pitch for the first time I discovered css zen garden: "you can redesign your website without changing the HTML!"
I sort of liked it at first. I even added the opportunity for my users to modify the CSS to add new styles, and share these to other members of the community via a configuration page. It was a neat thing but not many people bothered and in the end it made everything more complicated (and I guess I was really scared of vulnerabilities the whole time, what can go wrong with letting your users set the stylesheet.)
Worse, I think this new approach broke the web as it was: an explosion of flash-layout or photoshop--or-fireworks-cut-layout websites. It used to be beautiful. Now the web is just a series of websites styled by CSS. It's sad.
phones (and their screen size + apple killing flash) really killed the beauty of the web IMO. Now everything's an app.
Well you have that CSS zen garden thing nowadays. It's all the different media, screen sizes, user preferences. And instead of writing multiple classes that defines styles for different outputs you just have one and let CSS handle the differences. No need to duplicate classes, just semantic names.
it really only would make sense if we were serving pure xml and the webpage was the api for literally every webpage.
since that is not the case, tail wind is great, even the biggest complaint about tailwind, bloated html size seems like something you can just compile away.
Yes but the way we do HTML has also changed–for example by using JSX and reusable components. The issue of having to change markup in a lot of places to change styling doesn't exist anymore if you abstract that away in reusable components.
And using tailwind without a reusable components system is cumbersome to say the least. What is suggested in the documentation is to use editor features (multi-cursor, research and replace, ...) https://tailwindcss.com/docs/reusing-styles#using-editor-and...
Everything on the web became a lot more dynamic. Stuff like web apps obviously but even relatively straight forward info pages end up with dynamic filtering and elements of app like functionality often.
Given that, the separation becomes more of a pointless burden than actually doing anything useful.
That was back when XML was supposed to take over the world. We were going to style the same semantic content for print and web with CSS and/or XSLT. XHTML was the next big thing. Every web page was actually just a page.
We're not living in that future.
But the CSS ecosystem is still useful, and still adapting to our needs today. Tailwind might be considered one of those adaptations.
> The point is not to hide the complexity of CSS, but to provide access from the markup to enough of capabilities of CSS that you don't have to edit your stylesheets 95% of the time, when you alter the styling of a document.
This makes Tailwind seem like a lot of machinery (in the sense of bundle size, running code, and pseudo-language) just to avoid opening a file at dev time.
Layouts are often "collaborations" - the effect of multiple items interacting. You'd still need to open multiple files to understand what was going on. Or read the DOM in the browser. When I read component code, I almost always prefer it when the style _isn't_ in the same file as the JS. It takes up space on the screen and gets in the way of reading about the behaviours.
I don't get the propertied benefits. Granted, I've still not used it.
Really? Tailwind sucks but that's literally the only good part of it.
Locality is one of the most important things in code. If I'm reading line 38 of foo.js and something elsewhere in the app effects that line, I want that something to be on line 37 of foo.js, not line 158 of bar.js.
The problem with Tailwind isn't the co-locating of HTML and CSS. It's that it does it by adding an entire new layer of complexity that's basically a copy paste of an large standardised API with the names of everything changed. It's barely even an abstraction.
> This makes Tailwind seem like a lot of machinery (in the sense of bundle size, running code, and pseudo-language) just to avoid opening a file at dev time.
It’s not about avoiding opening a file. It’s about avoiding the risk and/or cost that comes from editing a stylesheet that applies globally. If you change existing rules, you risk breaking the layout somewhere you didn’t anticipate. Or, to avoid that, you treat the stylesheet as append-only, leaving you eventually with enormous files and selectors of ever increasing specificity.
Tailwind (or Tachyons) makes for ugly markup, but it solves a real problem, and it does it better than anything else.
If every selector in a file begins with the component class, isn't it the same as writing styles in the component JS file ? I mean, the only real benefit I see is the forced encapsulation in JS compared to "soft" encapsulation in CSS. But, it's something so trivial to learn and practice that the soft part shouldn't be an issue. And if it is, then it is time to learn some rigour, no ?
And in a way that same paragraph/criticism could have been written about Geocities in the early 2000's. Yet the simplified but imperfect onramp made a hundred thousand people more quickly understand their way into web development (including myself), than they would have without it.
I think one could argue that the raison-d'être of tailwind is to hide the Cascading part of CSS, and along with it a lot of the complexity of actually using CSS.
This is simply not the case. In order to use Tailwind, you need to know names of Tailwind classes, which are not part of the CSS standard. To say that Tailwind is just CSS is like saying that Ramda is just javascript.
> Your classes in your project are not part of the CSS standard either, by your definition
Yes, but my classes, by definition, are defined by me. The behavior of classes of a css framework is defined by someone else, who exposes an api for you to interact with these definitions. An api that you need to learn, in addition to just CSS.
It is no different from React, Lodash, Rxjs, etc. being "just javascript". They provide an additional DSL on top of the language itself.
The author mentioned, that Tailwind doesn't support the “perspective” style attribute - if it's correct (I have no expertise in this), then Tailwind is not just CSS.
There's a meaningful difference to my workflow of doing
<div className="px-4"></div>
versus doing
.mycomponent__wrapper {
padding: 0 1rem; // Don't forget the time to look up whether it's vertical | horizontal or horizontal | vertical because I forget all the time
}
then
<div className="mycomponent__wrapper"></div>
and toggling between files, and making sure the team knows my preferred CSS layout structure in the general case.
Plus, the solution for more complicated CSS is to just write it as CSS and to add the class directly like you would before. The point of tailwind is that I don't actually like or care about knowing CSS trivia, I just happen to know it. There's no value to me in doing things directly in CSS unless it's complicated enough to justify going to that layer. A helper layer is perfectly fine.
> Don't forget the time to look up whether it's vertical | horizontal or horizontal | vertical because I forget all the time
padding and margin go `top right bottom left` just like in a clock. So it always start at top and go clockwise. The two argument shortcut is just `top right` with bottom=top and left=right.
Regarding the choice of class names: you are using using wrapper elements routinely, outside absolute edge cases like border gradients, you don’t have current CSS skills. As mentioned previously current CSS means you can have a 1:1 match of HTML element to UI element for the vast majority of layouts, no wrappers required.
Current gen frameworks will put the styling inside the component so styling is literally a matter of scrolling down.
<div class=“login”>
…
.login {
padding: 12px 6px;
}
Yes you need to know the order I’ll give you that. Still less overhead than adding tailwind.
Ideally all components would be small bite-size pieces, where scrolling down wouldn't be a big deal. But in practice I could still see it being tedious, scrolling through a bunch of classes to find the one you care about.
Now if there is a go-to-definition for CSS classes, that would be quite useful. But I appreciate that I don't have to even think about putting a name to my styles with Tailwind.
If it’s a sea of nested divs, so it’s hard to find the right element (a common pattern among “I just know react” developers), then fix the sea of nested divs.
Ah but then you would have to remember and repeat those exact pixel values every time you pad something and update them in every place if you decide to change it. Or build your own system of variables in CSS, or use some awful CSS in JS solution.
Also means you have to think of a name for every component you want to apply style to which is surprisingly tedious.
The author set out to find reasons to dislike tailwind and found them.
I don't think tailwind really sets out to abstract away CSS, so that criticism doesn't mean much.
With tailwind you still need to know CSS. On top of that, you need to know how tailwind maps to CSS. From that perspective it's harder than CSS.
But of course, we don't connect styles directly to elements that much in practice because we need a way to organize and group styles. Hence connecting styles to classes and classes to elements.
In practice you end up with a styling language expressed as classes on elements.
But the app specific, ad hoc ones tend to bet messy, inconsistent, poorly documented, have many holes, etc.
Tailwind just gives you a well-thought-out, well documented, common class styling language. It's also nicely customizable, so you can use its tooling for your app-level stuff as well.
It does leave an app-level organizational hole, IMO -- that is, where do you express your app-level styling decisions. Tailwind has some features for this, but the grouping/sharing aspect is weak. But "component"-oriented frameworks fill the gap very nicely, making them a nice complement to tailwind.
I used it recently for a project with a custom design and it worked out very well.
I hope what you describe will eventually be true for me, but so far the purported benefit of not jumping around isn't being realized. After 5 weeks of using Tailwind every day, I still have to switch between my file and the Tailwind docs fairly often to look up whatever shortcut classes I need.
So far I just miss CSS modules. Having my .tsx and .scss files both visible in split screen wasn't so bad.
You’ll start realizing the benefit more when you use it on multiple projects. Tailwind will be consistent across your projects where you can’t always say the same for custom CSS.
After trying out Tailwind in one pet project I have to say that for larger teams it should not be used. Looking at the code now I get the feeling that maintenance would be a big problem.
A bigger project with multiple pages having full on Tailwind css classes peppered everywhere looks to be a nightmare.
Does anyone have experience jumping into an existing larger project with legacy tailwind all over the place? Would you do it again?
I have only used Tailwind on personal projects, but I can't imagine it'd be harder than "regular" CSS, which is generally somewhat append-only anyway (you need a lot of team discipline to tame that somewhat).
In fact, I'd expect it to be more maintainable, exactly because it removes the indirection of CSS classes. They're an abstraction that don't make much sense if you're already using components, and the very point of that abstraction -being able to reuse styles- is the very reason it quickly becomes append-only. With Tailwind, you can safely delete styles, knowing it won't affect styles elsewhere in your project.
This succinctly nails what I love about Tailwind. It gets rid of the cognitive load of reviewing a css change and having to think through how the change will ripple throughout the site.
I think the key with Tailwind is that you need to aggressively componentize for it to be useful. If your pages are 90% made up of small components than it can be very reasonable and pleasant to work with. If you have a lot of pages that define their own HTML it can turn into a mess very quickly.
I dont see a problem with big teams at all. You opne up the components HTML and see the styling right there, no doubts in your mind where to edit the styling (no stylesheets to find etc.).
Of course, this requires the team to have disciplin and make proper components so their not copy pasting tailwind classes 100 times
I've had some experience migrating large UI projects at work to use a design system based on Tailwind. Haven't faced any issue with Tailwind at all, even while integrating in existing projects.
Tailwind is a different way of writing CSS, with some guard-rails coming in from the design system consistency. Tailwind also provides sane defaults (rem over px, for instance).
If someone's bad at writing or thinking in CSS, chances are, they'd be bad at Tailwind too.
I've found Tailwind helps me focus on writing the CSS that matters. But just having Tailwind CSS in a project won't automagically fill one's gap in CSS knowledge.
This isn't bootstrap, where one can use some col-* utilities and magically get a grid layout that just works across browsers.
Tailwind is a bit lower level, and to achieve similar responsive layout, you still have to know how to do that with CSS grid, what the breakpoints are etc.
Where Tailwind aids here, is by providing utility classes that help with original CSS grid intuition. For instance, `grid-cols-2 sm:grid-cols-4 md:grid-cols-6` would be hard to achieve by hand, writing vanilla CSS or styled-components.
> A bigger project with multiple pages having full on Tailwind css classes peppered everywhere looks to be a nightmare.
Ideally, you would be using a framework to help organize code better. Most likely React or Vue or something similar.
In which case, you'd already have components.
There are more than one way to achieve same look and feel, with CSS. Similarly, one can apply some discipline with using Tailwind's utility classes, when building anything.
Two heuristics that have worked for me, are:
- Never use margin if you can, use flex-box and grid with gaps instead. Placing a children node is parent's responsibility.
- Write symmetric CSS. Prefer px over pl or pr, mx over ml or mr etc.
Using margins make it hard to extract some React markup as a reusable component. Using symmetric CSS gives you automatic RTL compliance without using any of the CSS logical properties.
Sure, there'd be times when a UI design cannot be implemented without breaking some of these. But in most cases I've encountered at work, building consistent UIs, have been easy for me and my team following these.
Happy to go into details with code examples, if anyone's interested.
”Never use margin if you can, use flex-box and grid with gaps instead. Placing a children node is parent's responsibility.”
Good idea, but importantly only applies to flex and grid layout, not paragraph-like blocks of content.
It is not a good practice to use flexbox for layout, especially if there are nested flexboxes. It takes a lot of time to recalculate such a layout, which can be seen when resizing a desktop browser, or when advertisements load on the page and the layout shifts.
”Write symmetric CSS. Prefer px over pl or pr, mx over ml or mr etc.”
Usually but not always. For example, text boxes can look more visually symmetric with less padding on the ragged side, while interaction-heavy mobile layouts may want to have a larger padding on the right to give the user something to safely scroll.
The symmetric bit is a good idea. I recently joined a team that maintains a multilingual LTR/RTL site so I'm learning some of these lessons the hard way.
Padding > Margin can also be a good idea, even if working vertically. Padding cannot collapse which is usually what you want. Obv, ymmv.
At work, we've built a component library styling readily available headless components from Radix UI, Headless UI, Reach UI etc. with a customized Tailwind CSS preset.
We had to use `rtl:` directive only in one component, where we were animating translation property, of a switch toggle. `translation-x-` is RTL specific, so we've to apply negative translation if `dir="rtl"` has been set.
Otherwise, this symmetric-utilities-only approach worked really well across dropdowns, modals, tooltips, buttons, inputs etc., even when we integrated these components in different existing products across multiple teams.
I hope one day Tailwind CSS team release an update with underlying CSS for px-, mx-* being replaced with CSS logical operators for corresponding properties. Not sure where the browser support for the same is currently.
This. Tailwind and react work very well together. Components then become portable to other tailwind projects. The best part is tailwind then only ships the CSS you actually use to the browser. Much cleaner than older CSS approaches like bootstrap. Has made me much more productive overall.
But CSS-in-JS was a mistake. Unless you want to start coupling your build tools even harder to get nonces on every compile, your CSP will require `unsafe-inline` which is bad for security. The simpler solution was to do CSS in CSS and keep your tools simple and minimal.
I had very few issues with just creating one scss file for every component module, ie ProfileCard.tsx and ProfileCard.scss, with sub components like ProfileCardimage being a nested selector in the scss tile. I don’t think you really need complicated design systems or atomic utilities anymore, just a bunch of variables for spacing, fonts, colors, etc. For any given component I knew exactly where to look for its styles, and it is all there. If the scss files becomes unwieldy as requirements change, it’s easy to just re-write it.
You could get the same benefits by using the `style` property though. The good part of tailwind is the part where it's all compiled down so it's not unnecessarily verbose in the HTML served to the client.
But you still have to have a config file, right? And the Tailwind docs. And then keeping track of when you changed something in your config that means the docs don’t apply 100%.
I’ve touched my tailwind config file a handful of times in two years. It’s not a problem. Tailwind just gets out of my way and let’s me iterate quickly without worrying about global side effects that always happened in other projects. I love it.
This feels like the wrong way to think about tailwind.
Every other UI framework or library that I’ve used felt like leaky abstractions. You always have to learn both how the library works AND how css works.
Tailwind isn’t even an abstraction, it’s just a layer of convenience to be used where helpful and ignored where not. The thing I love about Tailwind is that it feels like CSS. In fact, I feel like I know CSS better for having used Tailwind.
To start, it's ok to not like Tailwind. The author's complaints are valid in the sense that Tailwind doesn't really solve the edge-case problems they apparently have.
But the author finishes by saying "Maybe you really want to avoid coming up with names." And yes, I really do want to avoid inventing names and I'll tell you why.
If I have two projects both written in Tailwind, it's trivial to switch between them and make confident adjustments. On the other hand, if I have two projects with `.btn.btn-small`, there could be an infinite number of parent styles affecting that button in unpredictable ways. I don't just need to understand what `.btn` and `.btn-small` do, I need to understand _all_ of the parent selectors which could affect that button. The moment you write the equivalent of `body.single-page .entry-content .btn.btn-small {}`, your code is essentially unmaintainable.
All abstractions are reductive – the mercator projection sucks compared to a three-dimensional globe – but some abstractions are useful and Tailwind is very, very useful to me.
That's awful CSS. And nothing calls for it. There also are tools for linting and analyzing CSS that would flag this atrocity. Everything is there for us to use CSS in a good, simple way.
Well you could also use atomic design, essentially writing the btn and pagestyling separately and hoping they wont interfere.
Any tool will have a tradeoff.
It's so leaky that I have to constantly think about the thing it's supposed to abstract away.
For most of the work a frontend dev does Tailwind is just a nice shorthand library that makes life a bit easier for basic stuff. In that regard it's no different to Bootstrap, Bulma, Skeleton, etc. If you want to use it for absolutely everything, and you expect it to have every possible design element included, then you'll be disappointed. Just like you will with every other library.
90% of the time the abstraction works nicely. You can think in CSS and mentally convert to Tailwind pretty easily, or you can just learn Tailwind and occasionally have to delve into the docs when you're using quite niche styling.
It's not perfect, but that's not a reasonable criticism. No library is.
Tailwind is not an abstraction, it's shorthand. It saves you several bytes in the source, saves seconds of typing, and in return rewards you with a massive headache.
I'm a tailwind fiend, ie I like tailwind, but I can say it won't save bytes in the source if you use it the way that the docs intend. Tailwind is not very DRY so you'll probably end up repeating classes in source resulting in extra bytes if you just used a custom class repeated on similar components.
But you can create custom classes using @apply. If you're doing that alongside using it in components then it's incredibly DRY and far more efficient than anything else I've ever used in the last 20 years.
Tailwind's @apply just lets you apply Tailwind design tokens to CSS classes. It's useful for keeping designs looking consistent if you're already heavily invested in Tailwind. This is probably not much of an advantage unless you're working at a very large organization with many teams and web properties. And there are other CSS-native ways of enforcing design token consistency without Tailwind too. Open Props is a good example (https://open-props.style/).
@apply is also a great lazy way to just slap a string of Tailwind classes from mark-up into a class. It doesn't sound proper but it works in the context of iterative development.
Or Bootstrap, etc. This is why we didn't end up using TW for a large production app. It's really cool, but realized we were just ending up re-creating something like Bootstrap components using TW @apply.
Absolutely, I love @apply for this reason. But just look at tailwind's website, they don't exactly present this front and center, so I read their site as though they don't exactly prescribe the usage of @apply like you or I would.
but tangentially to this, that's why I like tailwind, its really not all that prescriptive but a tool that speeds up my development un-equivocally more than Sass ever has.
Tailwind is amazing when paired with React. It completely avoids the need for a parallel, poorly coupled, poorly scoped CSS file (or whatever flavor of CSS you're using).
Pretty sure tailwind has had the option to have the minimal CSS generated on-demand from the set of classes you actually use, for a year or so.
I haven't actually tried using this feature yet though (haven't had time to upgrade tailwind in the project where I've been using it). I suspect writing your CSS by hand could still be more efficient in per-byte output, but not enough to justify the productivity loss from not using tailwind
Someone can fact check me, I'm going off memory: I believe in v1 Tailwind (before they added the "JIT" compilation) when you were in dev mode it just had all the classes available at all times, and then added a step to the prod build where it would purge unused classes from the CSS.
Now Tailwind scans for which classes are used as you add them and builds an output from that. So if you only used `m-auto` the only CSS it would output in the final build is
Yes it does. You tell the compiler where your html lives and it keeps only the classes that you've actually used. This can be enhanced with a safelist of classes that might be generated by code. So you give it a regex to keep, for instance "all grid classes".
In development I like to generate ALL classes that are possibly available because it allows me to play around in the inspector and everything is available. But tailwind has that workflow in mind too with with Just-In-Time compilation. (I still prefer my way)
Anyhow, on a production site that I work on the final file size is 316KB (35kb gzipped). With a bit of tweaking the config I could get that down to around 250kb.
But writing CSS -- usually with SCSS, sometimes bootstrap, sometimes just totally DIY -- I have _never_ managed to keep my CSS well organized. It always eventually becomes an unholy spaghetti mess, including overrides of overrides.
So my interest in tailwind or "utility" approach generally (I have started using bootstrap utility classes more), is not to avoid having to know CSS, but to avoid having to write CSS that I don't know how to keep from turning into an unmaintainable unperformant mess.
(It makes me feel ashamed. I feel like I'm pretty good at writing maintainable code normally. But when it comes to CSS, I have never managed to learn how.)
I do see how you have to know more in some ways, and have two levels of abstraction to debug or reverse engineer when looking at existing code -- tailwind and the underlying CSS, which, yes, pokes through the abstraction. It does seem like describing tailwind as a "language" basically right. That "cost" may well be worth it though.
I think Adam Wathan's (the creator of TW) article [0] sums up the issues you are likely having. Modern CSS has an inherent dependency on the structure of your markup. This is a newer byproduct of modern design. Back in the day, you'd add something like `a { color: orange; }` for your entire site and be done with it. As sites got more complicated and design became a feature rather than an afterthought for websites, our needs changed.
Adam's argument relies on your CSS being tied to your markup in some way. If they are related, then the code should be co-located as well. Splitting things into separate files/names creates the scenario we've all found ourselves in where you are afraid to delete "old" CSS because you don't know if someone else has started depending on that behavior. By colocating the CSS with the HTML, you are now 100% sure that deleting that bit of "CSS" will not impact anything else.
This is arguably a good thing! It's long been a principle that code should be easy to delete. Tailwind enables you to "delete" CSS with confidence, in addition to its other main feature as a Token/Design/Style guide enforcer.
This kind of "colocation" doesn't scale too well: a family of as little as two pages should share a stylesheet for their common classes, ids and common structures, not consistently repeat identical CSS in multiple files.
The common technique of defining components encapsulating related markup and CSS makes repetitions in the output pages harmless because they are write-only, but it only moves the problem one abstraction step up (families of components with related CSS).
Isn't it still nonetheless better to arrive at that category of common classes as an outcome of 'component-first' co-location? These two needs don't seem mutually exclusive.
> a family of as little as two pages should share a stylesheet for their common classes, ids and common structures, not consistently repeat identical CSS in multiple files.
Tailwind really shines for this, but the caveat seems to be that it's much more useful when using a component-based frontend framework (React, Svelte, Vue, Angular, etc.)
I was recommending it to a friend who does wordpress development, but it occurred to me that it might not be useful (or not as useful anyway) in that environment.
For React, all the alternatives I've used have really sucked.
I prefer to use good old fashioned CSS modules for React etc. Tailwind is basically just a way of keeping your styles co-located with your components. For me, having `Component.tsx` and `Component.module.css` is good enough. People talk about jumping between multiple files when you're tweaking things but I just split my screen. TS on the left, CSS on the right, and go to town. In my experience, Tailwind makes React code really messy because now I have some potentially massive string on `className` instead of `className={styles.component}` or whatever
I used Tailwind v1 to build a WP theme years ago. It was still useful to enforce the design system and color tokens. With the Block Editor, I imagine that's even more true now. The hardest part is customizing all of the different modules/plugins to either use TW classes (via injection somewhere) or write a custom CSS file with `@apply` rules.
The WP theme templating system has partial file includes, so creating "components" is certainly possible.
Something I like about some newer web frameworks like Next.js is that stylesheets are component-scope by default.
This means that any stylesheet I use is inevitably going to affect, at most, one React component. And so I can call every actual container simply .container without worrying about conflicts or namespacing.
It's not possible really. As example we still cant use query selectors based on parents width. What do we do? Do we put all mobile styling in one big query selector with components inside or do we create many query selectors per component?
As soon as I got to the first example, ANIMATION, I stopped reading. If this guy is trying to figure out how to do animations and is getting mad at Tailwind, he shouldn't be using Tailwind, he's not the target market.
The call sign of a happy Tailwind user is someone who doesn't want to use Bootstrap anymore, switch tabs constantly to their CSS file, ever have to learn how the fuck animations work, and who instantly falls asleep when trying to learn the proper way to do CSS, even after having to deal with it for 20 years. SCSS? God no, just give me something where I don't have to think and I can make it instantly do what I want. I'll try random stuff for an hour until it works before I have to try and understand and take in something new, the resistance is real. I don't care if it's ugly, I don't care if it's MORE WORK, because for ME, it's not, and I can read the classes quickly and know what is going on and adjust it in real time alongside my content. Do I augment with regular CSS where needed? Yes, because the limitations can be frustrating, but I've only got like a handful of extra classes I need.
I'm one who hates to say I like it, because I hate the hype around it, but by god it works so well for me compared to anything else I have to do and I'm able to deploy and edit sites that look decent without being or having access to a designer, and those sites make money for me and pay my living.
Can I ever hope to compare to a proper designer or someone who has a solid command and understanding over what to me amounts to the most boring and droll thing ever: CSS? No way, they are wizards and they should hate this impure garbage, but for the rest of us it just works good and gets results with the least amount of thinking, which is all we really wanted.
I got shit to do, and it's the fastest, least resistant way to let me do it in the way I know how. It's not for everyone, but it fits the way I currently work, think, and how I value tradeoffs in speed, effort, debt, cleanliness and results. YMMV.
Is making a CSS abstraction the primary goal of tailwind? With my limited understanding, isn’t the main point to use a compact DSL to stop separating style into a different file, therefor ending the scourge of ever-growing stylesheets?
No abstraction is going to address 100% of the underlying concept, but that doesn’t mean it’s not useful. I’m on a team that is currently fawning over Tailwind. I am extremely skeptical, but they really like the idea of being able to wholesale delete legacy styles, and they like the idea of not having to learn all the intricacies of some css oddities.
Tailwind reminds me of Coffeescript: embraced as a language until ECMAscript woke up and started fixing some of the languages deficiencies.
I am skeptical of Tailwind. Personally I wouldn’t use it over vanilla CSS, but it’s gotta be solving some problem to be as popular as it is. I think that problem is that CSS kinda sucks to learn.
Many have suggested that Tailwind is some kind of replacement for knowing CSS, but I'm extremely skeptical of that idea.
I'm a fan of Tailwind, and use it a lot. There's no way you can use it effectively without knowing CSS. Contrary to the original articles statements, it's not really an abstraction. It has some very very minor abstractions like `space-between`, but these are the exception rather then the rule. Most of Tailwind lines up 100% with one specific rule in CSS. You have to know CSS to use it.
You either use a generic CSS or a generic HTML.
Everybody who picks Tailwind decides to use a generic CSS and a specific HTML.
I like the old school approach of having a clean and semantically correct HTML without any styling information. And then implement the "theme(s)" in CSS.
Makes just more sense to me and goes along with the idea of CSS - separating style and content.
But the recent adoption of tailwind make me think a lot.
Styling HTML with a few classes and css selectors has drawbacks: you have tightly coupled code that is separated, and modifying one or the others implies that you recalls properly its counterpart. There are methodologies trying to address that, but it never seems to be enough helpful.
This becomes even harder when you refactor/reuse things.
It is then worse when you want to maintain.
With an approach like tailwind, with non-specific css, the coupling is ensured, the css is re-usable, the patterns are re-usable, re-factorable with a single copy paste.
I don't use tailwind yet, but just using exclusively utility classes changed my ease in writing, refactoring, re-using and maintaining code by an order of magnitude.
> what's the benefit of Tailwind over style attributes on HTML tags
For example, you can't specify hover, focus etc. style attributes. You can't specify screen sizes either. Plus there are few Tailwind classes that cover several attributes.
Plus many of those styles are just unwieldy. For example, `drop-shadow` is `filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.1)) drop-shadow(0 1px 1px rgb(0 0 0 / 0.06));`
This. The secret super power in Tailwind is editing the tailwind.config.js and forcing standards. Then you have have something like only having four padding options per your style guide and them defined in one specific place. In style tags you could use a CSS var for this as well but you better hope you used it everywhere. Plus, that becomes super wordy: 'padding-left: var(--padding-1)' vs 'pl-1'
Oh I'm one of them..but incredibly clear shorthand is helpful for these kinds of cases. Writing code like `const a = 5; b = a/2; c = a/b` is pretty nonsensical. but in tailwind these things have meanings: p = padding, m = margin, then you have left, right top, bottom, (l r t b) and then X and Y. (so pl- mx- pb-) That is all of them. At the rate you use them it is pretty clear I guess.
It goes to say that it would be a computational nightmare to make computers understand styling, while HTML is very understandable for both humans and computers
I think the author nailed it on the head towards the end of the article.
> You still need to know CSS.
Yes, that's been the position of the Tailwind team from the get-go. In the author's defense, when users compare it to Bootstrap, that doesn't help.
The author isn't wrong I don't think with his observations, but to many people using Tailwind, I think the "downsides" are worth it for the massive gains in other areas.
One thing I believe will be changing in v4 (tried finding relevant tweets but came up short) next year, is the a more concise syntax to eliminate much of the repetition the author identified around nested selectors. For me personally, I would probably see those types of usage as an anti-pattern or a code smell. If you need extra classes on a structured list like in the example, I would opt to add that logic to the templating loop rather than use CSS to select every 4th option inside of every 2nd other option.
In my experience, Tailwind has only helped me learn and actually wrangle CSS to an effective degree. Most of the time, I'm looking up multiple articles on how to execute exceedingly simple things in CSS (the infamous vertical centering problem). Now, I only have one tab open, the Tailwind docs. All my searches give me the exact classes I need and I learn about Flexbox and all its useful properties, CSS Grids and all the other useful things CSS lets you do. I never once felt like I was robbing myself of some arcane CSS knowledge that some people gatekeep. If anything, it made CSS so much more approachable for me as someone who isn't particularly design oriented. It also made me think much more heavily about actual HTML and wrapping things in divs and spans effectively to style things in better ways
I don't really get Tailwind. Whenever I am looking at a layout, I am doing it in the inspector tools, not in the stylesheet or the html file. I don't care if the class is called top_bar or foo_bar or if the styling is done inline. I do care that is had a border-radius of 10px,. With tailwind I have to somehow know that border-radius is supposed to be "rounded". I have to learn a whole new language and constantly translate back and forth.
A lot of people seem to like tailwind though so I am probably missing something.
There's a tailwind intellisense plugin. Just type something into a class string and a bunch of suggestions pop up. Makes it incredibly easy - I learned nearly all of Tailwind in like 2 hours this way.
Except you should be learning a "language" anyway because that's what building a product is about.
To use your "rounded" thing as an example:
Design systems should have their own definitions of what a "rounded" thing is. The designs also probably have different types of border-radius based on if it's a container element, or a button, or a pill button, etc. So you define those as different types of "rounded". Small, medium, large. Round, rounder, roundest. They could be whatever you want. This way, your team doesn't have to remember that 10px = round, designers or PMs just say "round" and you use the "round" utility class.
Or if they don't like styling they can say "hmm what about 'rounder'?" and you use the rounder class.
That's what Tailwind aims to solve is to 1) define a common language across the team and 2) make that easily available for the FE dev to implement versus trying to cross-reference what "round" is.
The first example provided of building a custom animation is already outside of Tailwind's core use case of rapidly building common UI while only having to look at the markup. The occasional fine-tuning is usually when it's time to step over to your CSS file and write a custom component.
Anyone who builds UI for a living, ideally already having a well-developed mental model for how CSS works, immediately understands Tailwind's power in my opinion. Anything merits critique but this article just feels like rationalizing a preexisting bias.
> Anyone who builds UI for a living, ideally already having a well-developed mental model for how CSS works, immediately understands Tailwind's power in my opinion
Just chiming in to say I'm an outlier in this respect. I've been doing front-end focused dev for well over a decade, using every system imaginable, and I'm yet to see the appeal of Tailwind. I have tried it, and many of my use cases are supposed to be what it's best at (rapid prototyping etc), but I still dislike it in many aspects. That's fine though, if it works for other people then all the power to them.
It's likely that because many of the things I'm building are relatively bespoke, and therefore require breaking out of Tailwinds boundaries (like the authors examples), that I haven't gelled with it yet.
Tailwind is a high level language on top of CSS. It groups expected behaviors into groups that are applied through classes or directives. So in that sense it is an abstraction. However, it is as leaky an abstraction as preprocessor elements, native code elements in other high level languages. If you want to do advanced stuff, you can either fall back to "native code" in CSS or use some "meta-programming" through classes.
I've been using Tailwind for all my recent projects and it is an absolute gift. Yes, it doesn't take away the need to learn CSS, but it takes away a lot of the tedium in producing behaviors that are expected in modern websites. I used the lovely clay[1] library a lot to handcraft CSS before I started using Tailwind and I don't think I want to go back.
Tailwind is not an abstraction that makes CSS easier. You still have to know all the CSS.
The benefit is it makes writing CSS faster. Writing CSS in the markup just makes more sense. People say that markup and style should be separate to adhere to "separation of concerns". But in fact, markup and style should be coupled, because they both pertain to the UI, visuals, and aesthetics.
As a counter: I see a lot of bad markup ordering when you turn off stylesheets or use a TUI browser. You should be laying out your markup in a logical sense (within some reason) where it's easy to parse without styles and navigate with a keyboard—decoupled from styles. CSS grid and the `order` property let us easily move around elements for visual ordering and that this can (and likely should) happen shows that the data layer (HTML) has separate concerns from the visual presentation layer (CSS). Yes I want my first button tabbed to in your modal to be the primary action button even when it is displayed to the right of the cancel button and that's a heck of a lot easier to order it ‘correctly’ and style it in a different order for aesthetics or better visual parsing.
The thing I continue to not get, and I've used Tailwind enough to at least have an idea of what it wants me to care about, is why miles and miles of utility classes are better for that than, say, styled-components and an object merge.
I don’t think the author understands why people like TailwindCSS. It actually removes a lot of abstraction layers away from front end development. I just wish they stop adding so much to it that it becomes bloated. Keep it simple.
I don't think the author can stop. I think it's a business now. It's going to continue on and on. It suspect it will follow every other frontend library with major version changes etc.
Yes! Yes it is! And that doesn't matter a single hoot! Go and write your complex CSS to do your perspective shenanigans, that's absolutely fine. Don't be a purist who MUST HAVE UTILITY CLASSES AND ONLY UTILITY CLASSES. And you can't, and shouldn't, write tailwind while being ignorant of CSS.
You've set up a strawman and knocked it's head off, but I can clearly see you boxed a scarecrow.
Tailwind is not a CSS revolution, it's just a slightly easier way of writing (and learning!) responsive/interactive CSS. That's it. The hype is just that it actually fulfills that brief.
I think this is kind of unimportant, if you want to improve your experience developing frontends, establish a design system in close collaboration with the designers (use something like atomic design for example) and build abstractions that implement the design system around a component-based architecture. I feel like that's much more important to think about than whatever particular CSS framework you use. Also think about how you are going to optimize for LCP/FID/CLS (core web vitals), its gonna be hard optimizing that later.
It's amazing to me how many people who try Tailwind don't realize you can just... Write CSS when you need to, while using Tailwind?
I use Tailwind a lot, and I end up breaking out of it a lot. I don't think there's a designated 'correct' way to use Tailwind. It's a shorthand. When I need to do something that's easy in the shorthand, it saves me time. When I need to do something more specific, like applying some styles to all the anchor tags or something, well then yeah of course I'm not going to use Tailwind.
I think the hype machine is probably to blame. Many would probably come to these conclusions on their own, but they've heard people say TW is SO amazing, that they feel they must be missing something.
Basically an approach that leverages the advantages of utilities and blocks and embracing the `Cascading` in CSS instead of working around it, like BEM et al. likes to do.
Arguing that Tailwind is a leaky abstraction for CSS is like arguing that ORMs are leaky abstractions for SQL; hiding the underlying implementation isn't the point of these tools.
The biggest benefit is that you get a fairly well thought out API to work with. In the case of Tailwind, this a pretty flexible and good set of defaults that works for 95% of use cases. You can focus more on building classes for cases specific to your site, and not spend time rebuilding undifferentiated layout utilities.
From the many HN discussions over Tailwind, I've kind of anecdotally seen that...
A) Some experienced front end devs have a real issue with it, and
B) People who use CSS in passing, like me, tend to really enjoy it.
I want an abstraction over CSS, it makes me life easier. I'm not anywhere advanced in front end as the OP, so maybe that is the difference. But I realize it is what it is - utility classes. I don't get the issue here really - just dip down to CSS if Tailwind isn't doing what you want.
Tailwind reminds me a lot of email CSS, where all styles must be inlined. But just more terse.
I prefer SCSS, having used both as well as Bootstrap, just because I don't think Tailwind adds much more than it takes away.
CSS has slowly been creeping up on the frameworks too, providing native layout implementations that erode the benefit of frameworks.
But there's data in the widespread uptake of Tailwind. CSS purists need to understand why it has been so widely adopted, rather than just saying it's the wrong way to do things.
Because the truth is, in a typical development organisation, SCSS turns to mush just as quickly and easily as Tailwind does. Perhaps you can argue the mush is better because it's separated from the HTML instead of exploding class attributes.
But since Tailwind has a dev speed advantage, it's still ahead.
There's also data in what became the most popular CSS framework: BEM. This was specifically designed to contrain the cascade depth of CSS, one of its biggest problems from a maintainability perspective.
There's a saying that "one should program INTO a language, not WITH it", which I think rings true here.
It's not about Tailwind vs whatever. It's about what are the actual problems we are encountering with styling, especially at a birds eye perspective of years and organizations, rather than me and now, and how would we address those from first principles.
For inline CSS, I love Styled-System [1] for css as props. My components die and get redesigned too frequently to care for anything else. So I prefer them encapsulated in the Component itself.
I find css-as-props is better than a huge string of classes, as it much more readable and statically analyzable. I wonder if anyone is working on a successor to styled-system (though it works fine).
I've been working on a fork of a project that uses styled recently, and I'm pretty sure it's responsible for slowing down VS Code to the point of being unusable, though I don't understand why.
Having been outside of the frontend development world for innumerable years, I'm talking out of my backend here. But a cursory look gives me the instinct that Tailwind is kinda like Very Fancy Bootstrap. This blog post certainly makes the discourse around Tailwind to sound eerily similar to the discourse around Bootstrap.
Bootstrap got trashed regularly for being the Times New Roman of web development and any mention of it online would summon a howling pack of CSS purists. However, back in it's heyday, you could join a team and immediately start to make an impact because you knew the CSS class names and what they did. You still had to have someone around who knew CSS extensively to work out some corner cases. However, it definitely let the juniors get up to speed and when they hit one of those corners, provided a great mentoring opportunity to help them grow their knowledge of CSS.
> a cursory look gives me the instinct that Tailwind is kinda like Very Fancy Bootstrap
I was refuting this as it is not really the same, and pointing to you something (a UI library built with Tailwind) which is more logically comparable to Bootstrap.
You seem to have missed some words. Please point out how Tailwind is not a tool that makes working with CSS more standardized and simpler for someone just sitting down to your code base?
Literally the entire original comment was just that Tailwind fills much the same role as Bootstrap did, just with far more capabilities. Thus, it engenders the same flame wars that were fought over Bootstrap. You responded by saying, "It's a superset of Bootstrap."
Which is what I was saying by "Very fancy Bootstrap"?
Whenever a huge hype wave hits HN, I now just wait for the huge catches to appear... especially if it has anything to do with web platform stuff.
If something hangs around for a long time like Go, Rust, etc. and I see really serious non-hype-driven people buying in, that's when I figure there might be something to it.
Tailwind is awesome for those who don't know much CSS or dislike to work with CSS directly, or it is great for teams, that are not able to define general rules.
If you know CSS, you have huge problem to use a tool like Tailwind, cause you always feel like "how does this save me work?" it doesn't.
I'd wager that most people who jumped to tailwind and sing its praises never wrote good css to begin with (or never worked on a project that handled css well). Frontend culture is like that: there's a lot of novelty and fads that last a couple years.
The best css projects I ever worked on were led by people who were just good at css. They didn't write a lot of shared styles. That's my main complaint about poorly written js or css: code that depends on other code without good or self-evident reason. The argument "it's easier to write" imo doesn't hold up because you read code 10x more than you write it. Good code optimizes for reading not writing.
I'm partial to css that relies on primitives like the `rem` unit and css-modules.
This really hits why I've bounced off of Tailwind. I've largely been a backend/infra developer but for some reason CSS has always resonated with me; it makes a ton of sense to me and with HTML (or these days, a React or Svelte component) open in one pane and a SCSS file in the other, the purported benefits of Tailwind just don't exist for me.
I get why other people like it and I'll go with it flow when other people have started a project with it, but I feel much less productive when I have to go remember its syntax and behaviors instead of...CSS.
You have a shiny new tool called hammer and now everything seems to look like a nail to you. Tailwind is not made to completely ditch css. Its not a replacement, it just tries to make your life easier. At least in most cases in my experience.
Now i know why 99% produces faulty css that make problem on different devices. They rely on systems like tailwaind and think tailwind does everything for them.
Speaking as someone who attempted responsive design before tailwind, I can tell you Tailwind greatly simplifies the process of styling a site for multiple breakpoints
Life is full of trade-offs. This is one where I would always opt for the leaky solution. Ask the people who invented CSS why they built it in a way that is really really hard to understand - even for simple things.
PS: I know why. Because they built it without thinking about the users (web devs). Instead they were thinking about all the f-ing edge cases almost no one cares about.
I don't like it, too. Funny story: In my early years of development. My boss told me, that I should refactor the css of our application. We had a lot of styles directly in the HTML and I should create a css file with classes, to be able to reuse these classes. At that time I had no clue of css, this project should be a learning by doing. YES... Bad idea... So anyway: I did exactly that, what Tailwind does. I created a whole lot of utility-classes. I remember that our CTO yelled so bad at me, why I did such a braindead thing. I laughed so hard when I looked at tailwind, cause it's always reminding me at that time.
I think the author just missed the point. You’re not supposed to replace all of your CSS with tailwind classes when plain CSS classes make more sense, like the perspective and nth-child examples.
I used Tailwind for a year at work, never having used it before. I found it overrated, frankly, and not much of an efficiency boost. We had a "don't use inline styling or your own CSS classes if a Tailwind class already exists" rule. While the reasoning was understandable, it meant that every time I wanted to style or position a component, I had to browse the Tailwind docs to make sure I wasn't duplicating something. And Tailwind docs... let's just say they leave a lot to be desired.
We found that the tailwind VScode plugin was hyper helpful along with cutting down the unneeded in tailwind.config. Once you do that, most styling and positioning is variations on sizing, colors, and text sizes. Then the intellisense is pretty helpful to fill in the rest, some gotchas of course. `leading-` is an awful name for line spacing lol. A hardcore knowledge of CSS and all the governance you would use in vanilla is required to use tailwind however. It is important to see it from that angle.
What seemed to help us (and I don't condone this for everyone, it just worked for us) was to go more extreme: No CSS without a bulletproof defense in a PR. The only exception we needed to break in our large scale platform was to style an SVG progress indicator with complex gradients. Angular's behavior around [ngClass] not just adding classes but removing them also was a bit tricky. Personally the behavior in whole feels like a bug but I know it isn't.
In your case, you'd be better of grepping tailwind's source. You could even spend some time writing a shell script that turns your proposed style rule into a regexp and runs it wherever tailwind's css file is.
We have used a similar css utility library (Atomizer) at Yahoo for 8+ years. This has been used across many sites with a large group of developers touching the code. It has saved a ton on CSS size and duplication. We never force only atomic classes, for more complex use cases we push developers to write vanilla CSS.
Some of his points are valid about maintainability and complexity, but that can be resolved by building smaller components to share markup and classes. All depends on the use-case.
That is kinda a good thing. It allows the industry to understand the ebbs and flow of what people enjoy. Like the cycle of life, it allows for the industry to thrive.
I like how these people just NEED to find a ultra specific flaw to dislike Tailwind. I use Tailwind for 90% of a project, and write custom CSS for the rest. Why is that not allowed?
The funny thing is that while the Author is writing a blog post about how this specific feature ruins the whole thing...we wrote a large scale multi-million active paying user platform with it this year...and ~1% CSS. (Almost all of it is in modifying a SVG circular progress bar.)
Yes sometimes there is janky corners you will find (notably, the multiple copies of modifiers for elements that have a lot of (for example) hover or responsive properties) but for 99% of everything it works exceptionally well and has contributed to a dramatically faster app than the prior last gen product with an extremely tight style guide enforced by Tailwind's config.
I've used Tailwind for about 2 months now and I have to say that I think the author misses the point. Tailwind breaks away from having multiple style definitions away from the elements you're working with in your templates/views. With utility classes it is possible to see from the markup what styles are applied right there without having to dig through cascading style sheets that often hide in some bizarre area where the style is actually applied.
I cannot for the life of me understand why Tailwind gets so much exposure and generates so much discussion on HN. It is only barely interesting. As far as I know, all it does is wrap CSS rules into a form that can be used in the style of inlined CSS.
It's not new, interesting, difficult, or complex. I don't have much opinion on whether it's actually good or not (I happily use modular CSS), but the subject keeps popping up over and over.
I have recently started using Tailwind. I've been writing CSS since it was invented in the 90s. I'd consider myself a CSS expert. I'm using Svelte (components). When Tailwind doesn't do what I want, I write a quick CSS class. I also don't like the long class strings in the HTML, and haven't yet found a good workaround for that, but in general. I like Tailwind.
I am, but unfortunately modifiers are not supported unless you use layers, which don’t work in svelte components. So you can only use tailwind classes with no modifiers, which is mostly what I love about tailwind.
The workaround is to make components, so instead of having those long lists of classes copied around there's a component with those classes and the ability to take further classes.
CSS is a leaky abstraction - it's declarative programming with none of the power of actual programming. Basically the most unpleasant API I have ever used. I find it hard to care if the latest framework is a leaky abstraction for CSS. There's a constant translation between 'sane, decent mental models of layout' and 'real CSS' anyway.
In this case, the `class="text-amber-700` attribute isn't going to be much different in size than `style="color: rgb(180 83 9)"`, but tailwind has other utility classes such as ".grid-cols-3" which would be equivalent to an inline style of "grid-template-columns: repeat(3, minmax(0, 1fr));"
It also lets you set up a minification pipeline which turn the "text-amber-700" example above into something like
Write me a media query, or a hover state in inline styles.
You can't. So you fall back to classes and CSS and now your styles are split in the HTML AND css. Tailwind, in a very basic form is exactly this solved.
TW classes are a lot more concise and provide a "design system" vs raw values and browsers are good at applying classes vs parsing inline styles for every element.
It seems to be mostly a matter of where the performance penalty is paid.
Browsers either parse CSS (mostly) "ahead" of HTML (tailwind CSS classes), or as they parse HTML (inline CSS): they still got to parse a very similar amount of CSS, except if you've got the same "rule" applied in a number of places (though in that case, element-based CSS rules probably win-out).
Do you perhaps know of any benchmarks where the actual real-world effect is visible?
That benchmark tests something slightly different with a focus on repeated CSS rules (and all from JS even): it's not surprising that's faster, though it's interesting it's faster even from JS (I acknowledged expecting that, and that CSS rules per HTML element are likely even faster, eg. a td rule with all the styles on it would probably win over that too).
I do get the terseness point, but unless you are completely happy with Tailwind definitions, it makes code less maintainable rather than more IMHO: instead of having a familiar place to look up the "shadow" definition (if that's not really doing what you want) in your own CSS or HTML file, you need to look at tailwind CSS inside your dependencies, or inside a debugging console in your browser.
I am also unhappy about any code where you'd have to write even `class="text-lg"` a 100 times: perhaps I am still living in the foolish dream of semantic markup, and I would hope you can structure your document in a way where styling is context-dependent: so perhaps you put class="text-lg" on an "top-level" element, and then only adjust nested element text sizes where needed.
I love CSS, I'm relatively good at it. Didn't enjoy Tailwind until I really did. Working on a frontend project with other people Tailwind is fantastic. Everyone can see and understand what I've done and there's no trying to understand other people's style sheets, or see what they've done or anything else (especially with the VSCode plugin that orders the Tailwind classes properly). Sure, pure CSS does some bits better and I'll still use that for projects that are 'just me'. But it's great knowing that the next dev we hire can pick it up and go from day one.
As for the mentioned nested selectors (which I'm a huge fan of), in the next version I'd like to see grouped nested selectors. So instead of:
[&>div]:mt-4 [&>div]:bg-white [&>div]:px-2
You could do something like:
[&>div]:(mt-4 bg-white px-2)
Which I think would improve readability and significantly cut down on class bloat.
> But it's great knowing that the next dev we hire can pick it up and go from day one.
Presumably the next dev you will hire will be a frontend engineer? CSS is a core competency for a frontend engineer, whereas Tailwind is an add-on. If I were choosing a frontend engineer for my team, I would make sure there core competencies are up to snuff.
But I get your point. It's the same as the article, right? You still need to understand CSS to use Tailwind, so why bother? I guess each to their own. Maybe we'll regret this in a few years, but it works very well and feels much more maintainable for us now. I've certainly worked on enough projects (and, mercy!) had to pick up enough projects where the 'vanilla' CSS was absolute spaghetti!
Reading your Tailwind example, I must confess that I have no idea what "p-4" or "pb-1" are; or what the border-radius will be for the "rounded" class, or what color the "white" will be in bg-white.
> I've certainly worked on enough projects (and, mercy!) had to pick up enough projects where the 'vanilla' CSS was absolute spaghetti!
And I am very guilty of having written such spaghetti in my first big project :-) But authoring FE code as components, and encapsulating styles inside of components (with either CSS modules, or scoped styles) has helped tremendously. Perhaps web components will save us, by allowing full style encapsulation inside the shadow DOM, thus eliminating CSS-at-scale headaches altogether.
> I must confess that I have no idea what "p-4" or "pb-1" are ...
Of course! That's the Tailwind add-on, right? I guess the key being you can move between projects that use Tailwind and know it's a rem unit of padding all round and .25rem padding at the bottom. And when you come back to it 3 months later, you still know.
> And I am very guilty of having written such spaghetti in my first big project :-)
Oh, me too and not just the first! It's amazing how quickly things can turn to pasta when you're rushing to hit deadlines! :-/ But I think you're right, with good practice everything gets a bit more maintainable. Let's hope we get there eventually!
I don't mean this as a slight towards the author, but I don't see how this takes away from what Tailwind is good at. I never imagined it would be a one-size-fits-all utopian solution to CSS (an already great tool, in my opinion), but it is great at a set of things it sets out to be great at, which sometimes aligns well with my needs.
I don't think tailwind should be used everywhere. Sort of like a CRUD framework, it could really get in the way of doing bespoke or atypical things the underlying language can do but the framework or library explicitly wasn't intended for. Breaking convention can become a hurdle.
The reality is that the vast majority of API work (for example) does benefit from a CRUD framework of some sort, be it lightweight or otherwise. CSS is great, but do we need its full potential at every corner of the UI? Probably not. What we need, usually, is a consistent set of conventions we can shovel out an get good, repeatable, familiar results which benefit both devs and users in the long term.
Tailwind supports custom classes for exactly this reason. You need an escape hatch because it isn't the holy grail of all CSS projects. It's a helpful tool with well-known limitations.
If I need to batch out projects in my shop, I will build jigs and find the right blades and cutters for my machines. Then I'll rip through the various settings to get the pieces I need very quickly. This is like Tailwind in the workshop. If I need absolute control, I need various hand tools and a lot more time. Can I create something awesome? Absolutely. Is it inherently better? Not really. It depends entirely on what is needed in the end. Generally speaking, most of us just want a dumb box to put some stuff in. Tailwind will do that expertly, just as my table saw and router with jigs will.
Asking your tools to do something they weren't intended to do will cause headaches, yes, but it becomes more an issue of user error than tooling problems at that point.
So we are building an all new...rather large scale product for millions of users and have been using Tailwind since the beginning of the year. In my experience writing a production app the only miss in Tailwind for me from article is the syntax for multiple properties that require the same modifiers.
writing:
"p-1 md:p-3 md:text-h1 hover:md:scale-95 hover:underline hover:text-blue hover:scale-105" is super annoying compared to something like:
+1 this is my only notable sticking point with Tailwind as well.
If you could compute the names dynamically it wouldn’t be an issue, but alas.
Tailwind is really amazing, and I was a vocal naysayer for a long long time before eating the “mindset shift” cost. Easily one of the biggest productivity boosts I’ve seen in years.
This is a really poor take - the point of tailwind isn't to abstract CSS away from you. Its to structure how you write CSS.. its a CSS framework. and it does a fantastic job at allowing you to quickly build out CSS layouts with zero-runtime.
I've used pretty much every styling variation you can imagine, CSS-in-jS (styled components, emotion, component libraries), vanilla CSS, and I after landing on tailwind . I can honestly say I have never had so much enjoyment and velocity building User interfaces.
My understanding is that tailwind is a framework consisting of utility classes corresponding to css fragments.
If its missing a fragment you want, then you can add that fragment - either as a custom class, or as a tailwind "managed" class.
Managed classes basically mean a bit of magic (compilation) around sizing, etc is applied.
The compiler then strips out all the stuff that doesnt get used.
The "leakiness" that the author mentions seems to be focused around elements "injecting" styles into their child components. They then go on to suggest alternative underlying css that may be better.
Maybe this should instead be an issue/PR raised against the respective managed classes rather than a criticism of the framework as a whole?
I found that one can make Tailwind CSS utility classes appear vertically, if one's been using clsx library[1] (or something similar). clsx accepts an array, and at that point, prettier formatting kicks in.
You could have a React `<Button>` component's styling go like this, with clsx and Tailwind:
```
<Button
type="button"
className={clsx([
"inline-flex items-center", // how its children nodes should be laid out
"px-3 py-2",
"bg-gradient-to-r from-blue-500 to-indigo-500", // background color stuff
"rounded-md", // border radius
"text-white", // text color of children nodes
"outline-none hover:ring-4 focus:ring-4 ring-blue-500/40", // hover focus behavior
"disabled:hover:ring-0 disabled:cursor-not-allowed" // disabled state
"disabled:bg-gradient-to-r disabled:from-blue-400 disabled:to-indigo-400"
])}
{...props}
>
Click Me
</Button>
```
There are other benefits to using a library like clsx. Since clsx accepts array of strings and returns a joined string based on conditional, output of one clsx call can be consumed by another clsx call.
Although the author mentions some interesting points the biggest advantage that I find using tailwind is avoiding context switching. Going from the markup to css and then trying to remember what was the name of the class I was working with? And the thing inside, was is just text or a div?
It is true that I can have divs with a ridiculously long class, but that’s the moment that I know is time to make, say, an input component or a card or whatever and move up one layer of abstraction.
There are trade offs for sure but I’ve never been more productive or had less headaches implementing a design than with tailwind.
I feel I’m the only one rolling my TW keywords into classes when they get too unwieldy. It’s against the recommendations of TW and anyone, but it works much better than creating a new component for absolutely every tiny thing.
Eg .Btn for a bunch of styles that style a button element, then .Btn .—-large to make it large, etc, which uses more TW styles in my scss file to make it work. It saves me a ton of time and allows me to use the same template across many projects; if a color needs to change or sizes are different t I swap it out with css vars
I really like using Tailwind. But I mainly only use it for personal projects. I have some design and front end development background and I feel comfortable creating a design system from scratch. But, for professional projects I pretty much always use Bootstrap because it has a predefined design system that a lot developers feel comfortable with. I'm not quite sure why the Tailwind team has steered clear of having a prefab design system that gives you classes like `btn`. It seems like a major piece of the puzzle they're missing.
Agree 100%. I wish there was a lightweight utility framework that is truly just shorthand, i.e. if I know the CSS property I can predict what the class name would be. With Tailwind it's all arbitrary
My plugin supports this, but only if I happen to know the shortcut. When I start typing...
border-radi
...for example, the plugin doesn't suggest...
rounded
...because I didn't type anything close to matching that.
It seems like the only way to benefit from Tailwind without having to switch between your file and the docs is to invest time memorizing the many, many, many shortcut classes that don't start with the same word or letters as the actual CSS property name you already know.
This is a good take here, even as someone who loves Tailwind, the intellisense should grep not just the class name but the contents. `leading` is an insane name for `line-height`
When you only work with atomic css for a short period of time and come at it with something to prove like the author, chances are your thinking about it isn't mature and fluid/adaptive.
You don't have to only use single-purpose classes, nor is your work limited to the api surface of Tailwind.
What we do when we bump into dead ends, like the author's reference to `perspective`, is Write CSS. Tailwind makes _extending_ itself as easy if not way easier than other comparable libs (and with _much_ less duplication).
Oh boy. This is a fascinating read. I wrote about Tailwind css as an abstraction layer. But I use some of the same reasons as OP to convey why it is great.
This really was an interesting read. It shows the same thing can be seen as good and bad by different folks.
> The relevant consequence is that now, attempting to set a left margin using a selector with lower specificity — say, the selector generated by a Tailwind margin utility — will fail.
> It's essentially a small language you write in the class attributes of your HTML that compiles to a combination of CSS rules and selectors — an abstraction over CSS
That is not what abstraction means. If it is a "language" (as you describe) that essentially maps 1 to 1 of what the CSS itself does, it isn't actually abstracting anything away. The key trait of abstraction is information loss. Tailwind keeps you connected to the CSS you are using more so even than CSS in stylesheets does.
I don't think tailwind is built to solve the issue that the author is trying to fix. Tailwind provides a way to generate a set of consistent classes.
Instead of defining rules in style sheets they're associated directly to the element, which reduces the issue of having styles cascade all the way down.
The way people maintain CSS in ".css files" is really broken. Whenever something need to change quickly, a rule is appended with !important;
The utility class shorthand is nice for simple things. But there’s definitely a “too much of a good thing” point, where the “shorthand” becomes so complex that you’re better off writing proper CSS instead, whether as inline styles or in a separate .css file.
I think that’s the main failing of the Tailwind crowd, they want to “Tailwind all the things”, use their shiny new hammer for everything, even for things where it’s clearly not the best tool, like crochet.
I did not realize that Tailwind had spacing utilities. I know CSS and I've just been doing stuff like gap-3 for flexbox'd containers etc... It never even occurred to me to not do that, because like the article says, I know CSS.
Also, I really don't think tailwind is a replacement for regular CSS. I've found more success mixing them. "Promoting" a series of 10 utility classes to a semantic class name when needed.
this is the problem with programming laws like leaky abstraction. Just because tailwind is technically a leaky abstraction doesn't mean anything. Its the best thing that happened to CSS for me. This applies to all those clean code principles, OOP and functional paradigms and whatever best practices there are. Religiously following them just isn't practical in the real world and just brings about unnecessary pain.
"Tailwind is how _twitter_ Bootstrap was originally conceived"... Change my mind.
But eventually people started pushing their agendas into the code/styles and we end we a bloated solution that works for everyone except those that want things to go back to slim.
If tailwind continues to please the crowd, it is going to get bloated just like every other major attempt to murder Bootstrap did: RIP UIkit, Bulma, Skeleton, etc.
Of all of the CSS frameworks out there, tailwind seems to be the thinnest layer above CSS, and most likely to be used by people who already understand CSS extremely well. It's almost a convenience layer at this point...the coffeescript of CSS.
If you've gotten to the point where you're complaining about Tailwind CSS being a leaky abstraction, shouldn't the answer be obvious? Just use CSS.
~~You still need to know CSS.~~ I think its the most important reason for tailwindcss's success, as other UI framework builds new API on top of CSS, say in mui things like <Grid /> etc. tries to reinvent things in CSS for sake of simplicity per say but in reality its just more API for developer to learn.
Tailwind was the response to the "I need more control and customization than bootstrap or (insert framework here), but I also don't want to write a ton of vanilla, best-practice css."
You can easily add your own custom classes. You immediately jump to a complicated problem and say Tailwind is bad because it doesn't handle this edge case well. (btw, its not trying to handle it)
Tailwind is just another language to write CSS, at the same abstraction level as plain CSS, but with the benefit of being terse and in the same file as the markup.
Tailwind actually removes a large part of CSS's abstractions (The "Cascading" part), which gives the huge benefit of being able to copy paste code and know exactly how it will look.
CSS has done more damage to developer productivity than any other technology out there. And I'm including .csv's. CSS is over 20 years old and we as an industry have been spinning our wheels on how to do simple arrangements of rectangles the whole time. Truly, it is time to just bin the whole thing as a failure.
This is an opinion trapped in 2010. You can build both "simple arrangements of rectangles" and way more complicated layouts easily now. What would you propose as a replacement?
There's been some criticisms of tailwind over the years now that I've largely agreed with, but this one feels a little hollow. The point isn't to abstract away CSS. And the presences of escape hatches (above all being: *just use css, it's supported, well*!), is not a downside of tailwind, but one of its biggest strengths.
You should think of Tailwind as you would think of CSS shorthand classes (and not as an abstraction as the author misunderstands).
In CSS, there are lots of shortcuts: `margin: 0 56px 10em`,
`background: #ffffff url("img_tree.png") no-repeat right top;`, `font: italic small-caps bold 12px/30px Georgia, serif;`, etc.
You often have to reference the order and style of the rules. You cannot use them in all cases, and you may need to merge these shortcuts with regular rules.
But to call shortcuts a leaky abstraction that you hate is simply stupid.
Tailwind is a bunch of shortcut CSS rules. You may have to reference the docs as you get used to it, you cannot do everything with it, and you should mix it with other CSS.
But on the other hand, it makes your code much more readable, consistent, and easy to get out the door. Well, well worth the effort to integrate. Not worth bowing down to.
Shameless, but relevant plug:
Tailwind had, IMO, one major shortcoming, and that was no support for children/descendant/children. That was kinda fixed with arbitrary selectors, but I still recommend my tailwind-children[0] library to everyone.
Tailwind is absolutely awesome if you're creating JS components, and if you're doing that I have no idea how you could think it wasn't the best solution save for just not having ever used it properly. I can't see myself ever switching from Tailwind, it's the final form of css for modern front end development.
It hit me when I had to google a translator for tailwind. Why do I use tailwind if I already know CSS?
Then later it hit me again, why is it called cascade style sheet - it's supposed to be separated the style from markup.
And well why use an entire JS engine to rewrite some CSS.
The general feedback on the link is that it is absurdly specific and comes to some unfair conclusions. Tailwind is popular and loved by many for a reason.
Just a guy who waited years to bash on something and he still didn't manage to do any damage. Tailwind is awesome for me and many others. At least in the grid, flex, themes, just copying an example that works and looks as in the demo and many other things where it really shines over css.
So far I've found it very nice to work with as shorthand. The only issue I have so far is override scenarios for merging 2 class attributes as it isn't straightforward how this works unless you have a map ahead of time to remove class names that you want overridden.
Here we go again, HTML and CSS have failed at being a unified story, and until there's an HTML 6 or some redesign that takes this into account then we'll keep running into frameworks like this that make it easier to do things for most people
I think I could find annoyances of similar degree for every styling framework I worked with. I will still take that over not using these tools at all and reinventing them myself (as long as the tool offers an escape hatch).
_All_ abstractions are leaky, but some are helpful. For me, as an unwilling and inept CSS dev working on small low-budget projects, Tailwind is helpful because it lets me put all styling information in one place.
there is a different way to achieve the same results.
instead of encoding every possible rule into classes, a combination of flex box-classes, templating and text props could be used.
<flex container>
<li #if index % 3 ####css-prop> </li>
<other cases>
</end-container>
there is some repetition, but it will keep things simple.
same thing for spacing example,
have a margin prop on a flex box container and apply it on each container then wrap them into a flex container.
it will be easier compose to compose vs css class variation.
Plugging in a book aimed at developers for design - refactoring ui, which is also written by the tailwind author to help developers approach design easily. Highly recommended book.
I wish someone would read the original article about "leaky abstraction" and then use the term correctly.
The author looks more like: I heard leaky abstraction, tailwind is an abstraction, therefor it is leaky. Then shows "problems" with Tailwind (tailwind wasn't supposed to solve) that are not leaky.
Also several of the commentators here misunderstand leaky abstraction
"This is what I call a leaky abstraction. TCP attempts to provide a complete abstraction of an underlying unreliable network, but sometimes, the network leaks through the abstraction and you feel the things that the abstraction can’t quite protect you from."
TLDR: I disliked tailwind even though I never used it, so I used it to confirm my bias, criticize it based on edge cases, so I could continue my hate towards tailwind.
Tailwind has enabled me (a hobby developer) to build a bunch of personal project and small business websites quickly and without having to know much about CSS.
let's not forget the HN mob is mostly back-end devs who will cheer for anything that gives them a quick and dirty way to style websites. These people have never needed to maintain a front-end codebase nor think about design systemically.
Senior front-end engineer here! I hated, HATED Tailwind for ages. It made me super angry that it was glossing over everything that makes CSS great. The ability to write great, maintainable styles seemed lost.
But after a couple of projects using Tailwind, I actually think it's a really solid way to implement styling that scales well as a project/team grows. It's maintainable because it's tightly coupled to markup (like styled APIs), has great first class support for design tokens and once you learn the syntax it can let you express specific css rules in a way that's more clear and concise.
I don't know if it'll have much staying power as the front end community continues to explore how we want to define styles. But what is clear from Tailwind's success is people want high levels of performance, styles tightly coupled to markup, a first-class way to utilise theme tokens etc.
For now if I was to start a new project, I'd likely pick Tailwind unless there was a good reason not to.
Millions of paid-only users here on a tight to the styleguide platform we built on tailwind with a team of FE devs with > 10 years experience each: Works great, HTML is easy to read instead of cross referencing classes, bundle output size is dramatically smaller. I'm not saying it is all sunshine and unicorns, just there are different perspectives, gains, and losses.
Tailwind is essentially the CSS equivalent of eval’ing a huge string of minified code that is littered throughout your markup. It would be completely unacceptable in any other domain of programming.
Tailwind, in use is almost exactly how one uses SwiftUI. Yes it scrapes and evals in the middle but that is exactly how things like typescript works. The Eval's outcome is smaller package sizes than basically anything. None of this is a new idea.
Tailwind is like a tool developed with the motto that we can hide complexity for you wonderfully. I don't think hidden complexity is a good thing. I understand why people like it, but I don't like the way it's used.
Tailwind is 100% an antipattern, spitting in the face of well-written CSS. It is essentially a crystallization of the 'utility class abuse' anti-pattern. There is already a well-defined way to write CSS inline, no need to obscure it with 'helpful' utility classes... right?
In reality, I don't think that's necessarily a bad thing. When Rails came out, people ranted about how PHP was bad practices because it mixed display and business logic. Look at what the frontend has become now with React and Nuxt and the like, basically just PHP all over again. Is that bad? Well, people seem to like it, so I don't think so.
In other words, I totally agree with this article but I've given up trying to make any sense out of the frontend world. Tailwind is for people who don't want to learn CSS[1], which seems like a frighteningly large amount of web devs. But, ultimately, that's OK. I will continue to happily ignore it.
My hope is that will some CSS changes landing soon (in particular :has and nesting selectors) we will see more respect given to CSS as a declarative language for defining UI, instead of just some boilerplate to make your page look pretty.
[1]: see replies below, this is wrong :). nisegami said it much better: Tailwind is for people who don't want to use CSS as it was intended. It's like a simplified execution model for it.
>Tailwind is for people who don't want to learn CSS
This reveals a fundamental misunderstanding on your part about Tailwind. Tailwind classes map very directly onto CSS properties. You can't use Tailwind effectively without knowing about the corresponding CSS ideas (although you can be unaware of how exactly to apply them in pure CSS).
Rather, tailwind is for people who don't want to _use_ CSS as it was intended to be used. Named classes and stylesheets just don't mesh with how my brain processes these things.
You (and super256) are right. You do need to understand CSS to use Tailwind well, which is more or less the point of this article.
I should have probably said "it's for people who don't want to deal with cascading", but IMO cascading is CSS's most powerful property. I can see how it gets confusing though.
I think that's a fair take. Tailwind and css-in-js's popularity points to a mismatch between how people want to actually use CSS and how CSS was designed to be used. It looks like people want isolated components, not complex cascading hierarchies.
I think that when :has becomes viable, we will open to the door to CSS-driven declarative UIs as opposed to imperative JS components, but this is pure speculation :-). I believe that a development style that takes advantage of cascading instead of fighting against it could perhaps become one of the new 'schools' of frontend development. I do not think it will become the most popular one, though.
> Tailwind is for people who don't want to learn CSS
I wholeheartedly disagree with this. You need to understand CSS to be able to use tailwind. Tailwind's class names are close (most of the time identical, even!) to the pure css equivalents. Furthermore, concepts like flex and grid need to be understood to produce what you want.
> There is already a well-defined way to write CSS inline, no need to obscure it with 'helpful' utility classes... right?
Inline CSS doesn't support lots of CSS that is critically important, like media queries, pseudo selectors, etc. That's the big reason why inline CSS should generally be avoided. There's nothing intrinsically wrong with it otherwise.
You're almost certainly using a templating language to generate your markup anyway, so if you're worried about the need to repeat common styles then factor out the common style declarations into shared variables in your template language. Yes, it's a way to avoid writing CSS, but look what it gets you: you've reduced the number of languages and files you have to manage and context switch between when developing. Typically this is programming language + template markup language + HTML + CSS + JS.
Eliminating 20% of your cognitive overhead is nothing to sneeze at. You can add something like htmx and remove most of the JS too for a 40% reduction. Front-end development actually starts approaching something close to pleasant.
Exactly! I think a lot of people are reading my comment as a takedown of Tailwind but that was not the intention. My point is that these kind of quick and dirty tools that others may consider an anti-pattern can be extremely productive and useful, and even become the de-facto standard. Ultimately, what is and isn't an anti-pattern is just a cultural concept between developers (although it can certainly have its roots in hard facts).
And for that typical CSS usecase, I find Tailwind way better both for quickly iterating and for hopping into code someone else wrote. I love not having to bounce between and cross-reference 2 (or more!) files (HTML + CSS) for a description of a single layout.
I started using Tailwind at my job I started 2.5 years ago and after the learning curve of memorizing the commonly used class names I have yet to run into a situation where I wished we weren't using it. I also started adopting it in all my personal projects because it makes me so much faster at getting work done and the code is easier to maintain.
I really feel like people start with their conclusion that they don't like it because it's weird and foreign and then look for excuses to justify why they think it's bad.