I'm a "full stack" developer. Largely a backend dev who does frontend as required, including on side projects.
I switched to TailwindCSS a long time ago and I have zero regrets. Its so awesome I can switch to a project that is 2 years old, and make a quick layout UI change without having to look at old CSS files to find classes etc. I also can just find a tailwind class name and apply lots of cool stuff that I've normally found difficult to do via "pure" CSS files.
But I also feel that this is likely to be a thing that half prefer A, and half prefer B, and there is nothing wrong with either. In this thread is likely to be a 50/50 split between both camps, with different "ideologies" on how the front end should be done.
As the author of this article says - give it a go. If you like it, awesome. If you dont, switch back to another tool, there's not a definitive "right/wrong" answer to any of this.
That's how I see it - as a sole developer on a side project, Tailwind is a great force multiplier, much like tools like Hotwire/Turbo, Dokku/Heroku for deployments, frameworks like Rails or Django etc.
A large company with frontend specialists and CSS experts might not need Tailwind - and indeed they might find it gets in the way. Personally I find it lets me build and maintain decent UI layouts with minimum fuss. When I'm repeating myself with too-long class strings, I can either use @apply or wrap the markup in a component.
I’d say even at a large company this can be advantageous. Since most devs are moving into fullstack, it’s obvious to me when more backend centric people are doing frontend. I’d rather they reach for standard classes than do their mish mash of css brainstorming.
I had the experience of using a similar Atomic CSS framework to a large-ish company in the past, and maintenance was pretty smooth too. In fact I would say that maintainability was the #1 advantage for us in the long term.
Some people did have a visceral hatred of Atomic CSS, but even those people were able to solve problems with it very quickly, without having to dig on tens of CSS files that happened to affect a single component.
> ... without having to dig on tens of CSS files that happened to affect a single component.
Hmm, that would be interesting data to use to analyze the CSS quality of a site. If you used the sourcemaps along with a rendered html page you could find which elements had styling from the most separate css files which might give you clues on where to improve your CSS.
Is it normal to have tens of CSS files impacting a component!? In my world, the component styles itself, and its parent can tell it how to be spaced / positioned and themed (via CSS variables preferably). Anything beyond that seems spaghetti...
Of course it's the worst kind of rotten spaghetti. But yes, this is normal when projects are 10 years old, super large, and have been touched by 200, 300 or more developers.
There's only two ways to avoid it: having very small, very cohesive, teams, or using tools and methodologies that avoid this.
I've mainly seen this happen when the site/application is very product/design (non-tech) driven and the developers pull themselves and the code into contortions to deliver very exacting requirements. The goal is to deliver a pixel-perfect result at the end of the sprint, and the unfortunate waste product is the mess of CSS, markup and JS required to deliver it: which then becomes very fragile technical debt that can only be tweaked rather than refactored lest the whole stack of cards collapses. It makes little difference whether the team started out with a UI framework or not at this point.
Fair enough, I work in small teams and independently a lot. It does make sense you need some strict architecture / tooling to prevent it in a more distributed org.
This is one of those things that gives me the feeling the true "10x" engineer mostly just writes code to some reasonable architecture standard and does their best to avoid tech debt. Speed in the longer term means avoiding these situations if you ask me
Disagree with 2nd statement. Tailwind is awesome for frontends, the way forward is to learn to compose. As long as you use bem style convention, with simple "flat" selectors, you can use both sass and tailwind and write less css (instead of no css, which I find extreme and impractical).
However that also means its perfectly ok to have one’s own system (cf. twitch, github...). Why not use a standard though? Tailwind saves us so much time coming up with a solid consistét utility set.
If anyone familiar with how Tailwind works lands on a new project, regardless of its age, this person can immediately understand the front-end code in a matter of seconds, without having to look through thousands of lines of code in a separate CSS folder.
I don't understand why Tailwind is "harder to read", as the OP wrote. It makes it much easier to read as what the code does is immediately understandable.
That is simply untrue. Tailwind is great, but someone who isn’t proficient in creating css layouts is not going to magically understand the same layout with tailwind classes.
I had to eg. fix a stacking context issue (z-index) a so called full stack dev could not solve. Basic css technique.
For someone creating layouts from scratch tw is very verbose and templates can become difficult to reason through while you develop them. Easy to disregard for devs who just jump in a ready made template and make smaller changes.
Using Tailwind does probably establish a floor on the difficulty of quickly diving into a new project (assuming the Tailwind config hasn't been customized too much). That might be great if you're in the position to force your team to switch from unstructured/undisciplined CSS to Tailwind, but not in a position to force your team to use some even more structured approach that supports even better consistency and composability (like a set of components). Granted, Tailwind is probably intended to be used to create a set of components, although a lot of their official messaging (like Tailwind UI) seems to actively work against that approach.
I think it's because Tailwind is forced via a mountain of historical baggage to shove it's entire UI in-between two quotes with a tiny (practical) character limit when you might really like some tooling (IDE collapse, expand, summarize, tag) and some browser support (dynamically compiled styles).
I think there's more than personal preference at play here. The hidden benefit that the author missed is that Tailwind's (or any other atomic CSS approach) classes are immutable and all changes localized. This pays off hugely for large [enterprise] projects.
In a million-line codebase, you can add and remove classes from a specific element with 100% confidence that you are not breaking anything else. With class-based styles, even when using theme variables, there is always the chance you end up breaking something at a distance by adding a property to an existing class, changing a shared value, renaming a selector or changing it's precedence.
If you find yourself in this environment where dozens of people are making changes concurrently, and these issues are a daily occurrence, naturally you'll wonder how you ever worked with CSS any other way.
styled-jsx and other approaches can get you similar benefits but extra care is necessary. I mostly avoid Tailwind due to the lock-in, complex setup and slow build, otherwise might have used it for quick prototypes more often.
Our experience has been absolutely not with an inhouse atomic css framework we ultimately ripped out of a project. Something like pd-md (for "medium padding") gets applied somewhere, then the decision is made that e.g. buttons should have less padding unless they're in a dialog, so someone goes around replacing it with "pd-sm" on buttons except they miss some and other developers don't get the message and add new buttons still using "pd-md" as they just copied and pasted the styling from a button that hadn't been updated and all of a sudden different forms have different padding on all your buttons, something that wouldn't have happened if making a button was just applying class="button".
For me it makes sense to create a component class in that case, using Tailwind‘s `@apply` to add the generic padding:
.button {
@apply py-2 px-4;
}
This ensures CI elements are styled the same way everywhere, but still relies on the Tailwind config to figure out what „2 abstract units of vertical padding“ mean in your application.
No, I actually love CSS variables. But they invariably will be abused in the long term. What you called medium padding might suddenly be decreased to be a value lower than small padding, and that’s the point where it all starts to go to hell.
The point of Tailwind is that it’s a straightforward way to handle all the CSS complexity and put the moving parts into a single config file that works the same everywhere.
> What you called medium padding might suddenly be decreased to be a value lower than small padding, and that’s the point where it all starts to go to hell.
Would it be strange to define p-2 to be smaller than p-1? Yes. Exactly as strange as defining your padding-medium variable to be smaller than padding-small.
I'm pretty skeptical about lock in. If I couldn't use tailwind tomorrow, I think I could rewrite the few dozen minimal utility classes I need in a matter of hours. IMO the implementation is a convenience.
The slow build is definitely an issue, although that's generally only a factor when you're customising Tailwind, not when you're just using the classes in your HTML. (I'm sure you know this, just adding it for clarification).
However, the Tailwind team are very close to releasing something that is, apparently, going to dramatically speed up build times (source: Adam Wathan's recent tweets).
I never got the point of Tailwind: having an element with utility classnames on it that each add one CSS rule, like class="flex flex-wrap" doesn't seem any better than just having the equivalent inline styles on it. Sure, the Tailwind utility classes are shorter, but the abstraction doesn't simplify anything. It's just some set of aliases you'll need to have memorized, and it's just moving the one-off combining of styles from the inline style property to the class property. It seems like something built to superficially follow the common wisdom of avoiding overusing inline styles.
I want to echo the author's recommendation of styled-jsx. I've been using it with React for a few years now and love it. Like Tailwind, the styling is conveniently co-located with your elements, but it's just regular CSS properties with their full power instead of a set of aliases crammed into the class property. It also encapsulates the styles to the component's own elements by default, which is very good at encouraging making encapsulated components. The codebase I'm working on used to have a mess of CSS files, and CSS files for various screens often messed with the internal styling of common components used within the screen which would regularly cause us surprises whenever we updated those common components without realizing how they were abused across the application. Now that we're using styled-jsx, proper component-level encapsulation is enforced by default, and it really helps guide us toward making the components themselves be responsible for their own styling needs, which keeps things much more understandable and more local with less "spooky action at a distance" (external styles modifying the component's internals).
In my experience, the real convenience of Tailwind over inline CSS is using all the variant classes (https://tailwindcss.com/docs/configuring-variants) like hover:font-bold, md:w-full, group-hover:text-gray-500 etc to compose your styles. It's not possible to use pseudo classes like :hover in inline CSS.
I've also found the tailwind.config.js very useful - you can load it up with all your custom colours and fonts. It's much easier to refer to text-primary (for your primary brand colour) than remembering a hex code and pasting it all over your markup :)
That's true, but not for media queries or pseudo selectors. I suppose with CSS custom properties it would work something like this (please correct me if you know a terser way to use defined colours and weights):
<span style="color: var(--color-primary); font-weight: var(--weight-extrabold);">my text in primary color and extrabold</span>
I believe Tailwind's syntax is still far terser and more manageable:
<span class="text-primary font-extrabold">my text in primary color and extrabold</span>
When you have lots and lots of styling this quickly becomes important
OK, but my assumption was that this syntax was proposed as an incentive to use Tailwind, rather than trying to cram custom properties into style attributes.
If I’m going to use custom properties it would be in a way that plays to CSS’s strengths.
Same here, and I'm also a bit terrified by the popularity of Tailwind. It makes me wonder if I'd have to resign from nice project one day because it is stuck in the framework. I think that more projects in Tailwind might mean less space for skilled CSS people.
I believe that Tailwind is a trap for people that don't like CSS, because if they one day come to a project with regular CSS there will be a lot of unlearning before they will start working at full-pace.
I might be biased because I love CSS and I find it the easiest thing in web-dev, especially now - without IE in the way and with flexbox + grid fellas, not to mention components. It gave me a lot of guidelines how to think about abstractions and how to build them. This translated nicely to other aspects of programming.
> ...Tailwind is a trap for people that don't like CSS...
I can't speak on the validity of this for all devs, but for me, I really enjoy CSS and I love Tailwind too. CSS is there for an escape hatch when I need it, but then I can use the utilities for a lot of mundane styling and placement.
Tailwind can absolutely be used for boring layouts and designs but can also be used for really cool custom stuff like this Diablo 4 landing page from a few years ago[0]. People made cool stuff with Bootstrap and then a bunch of crap also got made.
Tools ebb and flow and it's up to us as devs to find what's working for us now and then get the work done. Worrying about the future before you even get started doesn't make sense imo. The reality is very few sites are being worked on continuously for more than a few years, so trying to optimize for that potential maintenance burden doesn't make sense. If your site continues to grow and it becomes painful, that likely is a good problem to have and you can address the issue when you have the team and budget to do so.
If you think Tailwind means less space for “skilled css people” then doesn’t that mean Tailwind lowers a barrier for entry? Kind of like saying Java or C# reduces the need for skilled assembly programmers? If it does lower a barrier for entry, isn’t that what technology is supposed to do? Honestly, as a new user to Tailwind I think it makes css more accessible to me - it simplifies it to the point that I have a much better understanding of flex and grids and other things than I had before. And I do try to learn how the underlying css works, but tailwind is just a better design language for me, I find I am more productive thinking in Tailwind than thinking in raw css. YMMV of course, but some of us find Korean easier to learn than Chinese and at the end of the day we are both asking for a glass of water or where the restroom is - it’s just that for some of us one language is easier than another.
Criticism of Tailwind ranges from 'it's just inline css' to 'it's too easy, people will unlearn css'. I see Tailwind as a return to a simpler use of CSS. Comments on this thread talking about 'just write some cascading css' have perhaps not had to deal with the layers of css preprocessor abstraction that have developed.
Tailwind is much closer to raw css than some of the SASS, LESS, and Compass mix-ins I have had to wrangle.
Tailwind doesn't mean less space for skilled CSS people any more than design systems mean less space for skilled designers, or React means less space for skilled JavaScript folks.
Tailwind is a tool that's absolutely for skilled CSS people (you still have to know what everything is doing). And it is much more maintainable for a large number of people working on styling.
Do you? I'm sorry but Tailwind takes quite a lot out of the CSS equation. You only have to learn what each property is doing. Then for example C for cascading, being a great feature of CSS, which with Tailwind you don't even need to know it exists.
Yes, you absolutely still need to know how CSS works. You're still using the box model, you're still using floats and flexbox and negative margins to position things, and the most important aspects of cascading still work.
Tailwind is just shorthand for CSS prop/value keys that also gives you an easily customizable and maintainable design system, which an increasing number of developers understand. That means that you can be productive immediately on a new codebase instead of having to spend hours getting your head around the multitude of CSS files that may or may not have been organized in a way that makes sense to you.
> you're still using floats and flexbox and negative margins to position things
See - floats and negative margins are one of the code smells if are used to position things (yes, they have valid applications but in very limited use cases) that make me believe, that if you are still using them in 2021 then my worries about how Tailwind make dangerous shortcuts are valid.
You don't need to use them, but since they are valid ways of positioning things in CSS, Tailwind has utilities for them. They're as 'dangerous' as they are in handwritten CSS. You can get by with only using flexbox and absolute utilities and that's great.
> class="flex flex-wrap" doesn't seem any better than just having the equivalent inline styles on it
It is better than inline styles, though. Inline styles can't use media queries or pseudo-selectors, are difficult to override due to having a too-high specificity, and you have to copy values around (CSS variables also solve that though), among other issues.
Could almost just instead add a class to your html, and at the same place as the markup add a style tag inline writing exactly what you need. Css doesn't have to be one huge chunk. So instead of
<div class="lots of stuff">... or <div style="lots of stuff">...
That's basically how elm-css[0] does it. One writes css in the attributes of elements, and then when it's converted to DOM-stuff the css is extracted and classes created (or reused if similar). Since it's all elm-code one can reuse variables, call functions, import styles from somewhere etc
If you do it that way you have to give a name to everything. Imagine writing javascript but every expression has to have a name, its all globally scoped, and one expression cannot refer to another one by name. There's a lot of utility in not having to name everything
Sure, that solves the problem, but is still very verbose and doesn't really help with consistency by itself.
At this point one has to ask themselves if they're "avoiding inline styles" (or anything that looks like it) for a true technical reason, or just because of cargo-culting.
You can do pseudo inline styles by just putting a <style> tag after the element which will let you use those. I think the argument is that tailwind isn't _conceptually_ different than inline styles even if there are a few minor technical differences.
Your solution is also not conceptually different from having inline styles. In fact it's even closer to inline styles than Tailwind, since Tailwind is able to enforce consistency.
I love how these "developers" who apparently never had to develop a complex layout just hate on stuff they don't comprehend.
I mostly use Bootstrap, specially the utilities like the grid and I use a lot of these classes. It simple makes your job easier and plot twist, if you endup migrating you CSS framework without any need I got bad news for this fellow.
Yep. Bootstrap is a great example of how developers of different walks of life and different levels of experience are able to grasp helper classes easily.
You have just never done a responsive design. Inline styles can't be overridden on screen size and having all the styles hidden behind a random class name makes it hard to figure out what's being specified but if class names tell what styles are applied, you don't have to go edit part of a css just to change margin size.
I feel like an old man yelling at clouds, but I actually like CSS, with classes, specifity, and the cascade.
Maybe the difference is that other people build apps with lots of components. When I write HTML I mostly build web pages - a lot of text, some images, and maybe a menu.
I need to be able to tweak properties among a lot of different elements at the same time. E.g. change the font face on all elements in the main area, change the color of all links that are not special links, rotate all titles and underline them, and so on. It's an iterative approach, as I evolve the design in HTML (I don't have a designer team that hands me a psd I just have to copy). To do this with Tailwind, you'd have to use components, and you'd have to add another layer of abstraction to affect the right components together.
And I know nobody really uses CSS Zen Garden style themes - but it is great to be able to take a HTML snippet and use it in another project with minimal changes and a different CSS design.
CSS has shortcomings - it's missing a way to "include", it could have more complex selectors, it can get unwieldy in larger projects - but it is also does a couple of things really well.
I don't really use CSS frameworks personally, I find they tend to complicate things. Though I realize this philosophy may not work for everyone's use-case
Fair, is just that when I see all the css you have to write just to make a button pretty I shudder ;) It's fine I guess if your task is to only write css.
So by components you meant react components not css components?
Yeah, React and other similar component-based frameworks
The thing about writing the CSS to make a button pretty is that you only have to write it once (it's also usually no more than 10 lines), and then you can reuse it as much as you want. So forgoing a framework has some up-front cost, but in the long run it amortizes out and makes things easier to maintain imo.
Now, if I were churning out a new website every week or every month I would not be starting the CSS from scratch each time. I would probably carry around some starter CSS from project to project myself, though this would also be a good case for a framework.
Same here. In personal projects I just "handwrite" css (with stylus). It's simple & modular enough alone. At work we usually use a "framework" (sort of) to make teamwork smoother.
I think the styles everywhere thing depends somewhat on how you create components.
For example I have used Tailwind with Styled Components so I have isolated CSS for components and interactions, and consistent classes for layout.
It really makes maintenance a dream. When you update a component it is clear what CSS is tethered to it, so you don't accidentally leave unused classes around or tweak classes that are used elsewhere with unknown results. The bigger the app, and the more developers the more this becomes useful.
Of course for personal sites and blogs and projects many tools are overkill. But I have saved so much time, bugs and effort by moving to Styled Components. Tailwind feels like what I previously used bootstrap for.
I can hand write the CSS but I want to be able to quickly switch columns and fonts and alignment in a cross browser, mobile friendly way while writing the HTML on the first pass when working professionally.
Without Tailwind: guess at what the proper class name is, use it where you think it makes sense, eventually find out you got it wrong and have to fix everything.
With Tailwind: defer decisions about assigning classes until you've built enough to see what the proper abstractions are, then just refactor out the repeated utility classes. There's even plugins that will consistently sort your Tailwind classes so that refactoring can be automated by simple search and replace.
The irony is, you're the niche case, and from now on, will always be.
Almost everything on the web is basically an application, or runs on an app. Anything based on wordpress is an app. On Wix, or Rails, or whatever. They're all apps.
Almost no-one has static websites.
So your use case, which CSS might actually kinda fit, is the niche that CSS should actually ignore, or at least treat as a 2nd class citizen.
I'd say the vast majority of words online are in documents, not in apps.
Wikipedia is documents, news sites are documents, wordpress blogs (that are not shops etc) are documents. Even in this forum, when threads are locked after some time, they become documents. Even if they are dynamic behind the scenes.
Naturally, if you are writing something like Twitter, Gmail, any SAAS app, ... you need a different approach than when building websites for documentation, essays, news, and so on.
It's all CSS at the browser. Anything a utility CSS library will provide will eventually have to use the same APIs. It'll either be more low level to support more abstractions, or it'll be equally low level to what normal plebes would write.
You're using CSS instead of styling. That's what we're talking about. CSS is a particular styling method (particualrly poor according to a lot of our sensibilities). I've used a fair few, and CSS has to be the most frustrating of them all, even though some had higher learning curves.
No, I’m using CSS because that’s the actual styling API used in the browser. I’m not sure what else you’ve used, but if you’re styling in a browser, you’re using CSS. Even if it’s something that abstracts it or ultimately compiles to it.
Edit: just as whatever tooling you use to build content or dynamic runtime interactions in the browser are ultimately going to be HTML and JavaScript respectively... even if those aren’t the languages you wrote.
I understand the author points, and the article is well written. But, I moved to tailwind for different projects and now I use it nearly exclusively.
I don't want to argue whenever it is good or bad, but it solves my problems. When you are deep down some html component, being able to style it without having to find the css file is very pleasant. The code is also more maintainable as there is no "domino effect". You change what you want to change, and you are done.
As for vendor lock in, tailwind is MIT licensed, I don't see the issue here. Of course if you use X, you are going to depend on X. And if they release a breaking update, just pin the old version. I'm happy with improvement in tailwind 2, but to me the framework is complete, I don't mind it being frozen.
Concerning the long lines, I agree, but you can just put newlines between class names. Class name is a cdata list, newlines are ignored: https://www.w3.org/TR/html401/types.html#type-cdata
What I do is that I group classes by function, like color on one line, margin/padding on another...
> deep down some html component, being able to style it without having to find the css file is very pleasant
Is this a template based project with global CSS? That is not an issue at all if you're using an actual component system.
> tailwind is MIT licensed
I don't think the lock-in has anything to do with the license, but how hard it is to migrate away from it. You're locked to its build tooling and converting the styles back to anything else is a rewrite-everything-from-scratch proposition. Whereas migrating from say, styled-jsx to styled-components is a lot easier.
> Is this a template based project with global CSS? That is not an issue at all if you're using an actual component system.
Yes, I use phoenix live views, which is just HTML templates with global CSS. I know there are tons of "real" CSS component systems, but live views has been really a life saver to me, and I don't need offline apps.
Concerning the lock in, I think it makes sense only if the vendor will stop supporting it. I mean, if it works, doesn't change it, even if it means forking the repo and having it sit somewhere. The security and "bugs" are handled by the browser, the CSS framework can just be stuck in times, it shouldn't be an issue. Of course if CSS specs changes drastically, it might be an issue, but it would be for any other CSS solution. Also, we are talking about class names, this is fairly standard, tailwind didn't invent "utility-first" CSS, maybe not a drop in replacement, but I don't see that as a real lock in.
> Concerning the lock in, I think it makes sense only if the vendor will stop supporting it.
I believe it's still not the point. By vendor lock-in, the author meant that if one day for any reason (maybe size of the bundle due to many unnecessary class variants?) you will have to go away from tailwind, you will find it either extremely time consuming or even impossible (for example due to time/budget limits).
> The same could be said about any framework or language or tooling
That's simply not true. The knowledge of Tailwind's class names, media queries, and tooling is not transferrable, whereas styled-jsx/styled components/css modules/emotion are all still based on CSS syntax and applying classes, moving between them is vastly easier than to/from a framework like Tailwind.
Moving from AngularJS to React is not the same either. Understanding the way that data moves through AngularJS does not map directly to the way that React moves data through the system or how AngularJS updates the DOM vs React and all the idiosyncrasies involved.
Same is said for moving from Bootstrap to some other way of managing your styling.
Different tools have different naming, different "class names", different "media queries", and different "tooling".
I can't take my direct knowledge of Bootstrap 3 and use it in a styled-JSX world.
Moving between frameworks is always going to be difficult and require rethinking how things are built.
That was about CSS/styling frameworks only. Unlike application frameworks, the underlying tech and knowledge of CSS is the same, so you're really comparing apples to oranges.
"I am fortunate to have only worked with Tailwind CSS in local sandboxes, and not in any production projects or on an actual team of other devs."
Does anyone else get frustrated when people post blogs like this without actually using the technology in any meaningful way? I was also skeptical of Tailwind, and disliked it for the first 2 weeks or so of using it, but now I'm not so sure.
This reminds me of the phenomenon in outdoor gear where 75% of the reviews are people who bought a tent and set it up in their backyard and for some reason deigned it necessary to write a review.
I thought tailwind was a terrible idea when I first looked at it. Many months later, I tried it on a side project, and really didn't get it at first, thought after ~2 full days of working with it I felt very productive. The people who dismiss things without trying them will continue too I suppose, I just hope I don't end up having to work with them in a professional setting :P
except that shows that you haven't used tailwind at all if you think it's a 3MB CSS file... it's literally a postprocessor that strips out all the unneeded styles from the palate before you ship it. much, much smaller than 3MB.
Dev mode on any kind of frontend framework sacrifices bundle size for developer productivity. I've never worked on a Tailwind project that ended up with a CSS file larger than 11kb in production for a whole website, and that's what ultimately matters.
Why do you have to double down on this stance if you admit to having never seriously used it? Debug builds in any low level compiled language are also larger, because they include useful debugging runtimes, are you also against that? Sorry if I did not use the exactly right words to explain this, or if I too am just wrong about whatever you're talking about. Where does this anti-frontend-engineering madness end?
How on earth is that an admission? I said I decided not to use it right up front.
> Where does this anti-frontend-engineering madness end
I love frontend engineering and I would work on a tailwind-based project if I had a strong need or desire to work on it for other reasons. If I was picking between two projects and all other things were equal, I'd choose the non-tailwind one, though.
Sorry, I was a bit rude to you in my first message, and projected my being upset about a lot of other anti-frontend sentiment I was into to be honest!
I think we’re on the same page about generally picking what’s right for a project, even if some of our individual choices don’t line up— and that’s totally fine! We’re lucky to have so many free tools tailored to so many specific needs, and it’s okay when some of them are very similar, they can still both be valid!
Their initial comment shows just how little consideration they gave to the tool. not even a cursory glance. and let's be real here... 3MB for a developer build of something hosted locally is a weird nit to not consider something for.
Yeahhhh - I feel like if people had to qualify their opinions and comments on tech with in what capacity they've been working on it (professionally, personally, in 100 person organizations, 1000+, etc), then 90% of all internet arguments on this sort of thing would end before they even begun. ("I think all JS-related tech is stupid! Also my main exposure to it has been through looking at the Github page for React once..." oh boy.)
I'm always heavily skeptical of anyone who has a take like this without actually trying it properly. It's basically:
"I am fortunate to have barely scratched the surface of the tool, missed important details of how it works, and not used it in the situations where it becomes a lot more valuable."
The first week or two of using Tailwind is indeed awkward and a bit frustrating, but after that it's like a switch clicks and 3x productivity is unlocked. Especially if other devs are working on the codebase, or will need to in the future.
We use it in production for about a year now. We never had any issues with tailwind or how the markup looks. In the end you put that into meaningful (react) components anyway.
so much this! I started tailwind not particularly liking it but intending only to use the grids which I did find really nice. It ended up taking over all of my css needs because it was so pleasant to use once you got into its way of working.
And yes, I've handrolled my own and used bootstrap and bulma previously.
Tailwind hits a sweetspot for me when I'm trying to knockout components fast.
I had to stop immediately at “Tailwind makes code hard to read” and you’re telling me your home rolled css solution is any easier to read and understand? I would very much argue against that, as a home grown solution comes with zero precedent about how it works, so you have to go reverse engineer it from one or more source files, whereas tailwind is tailwind is tailwind in every file in every codebase.
It’s okay if you don’t like something, but if you’re going to publish a hate piece like this you’re going to get criticism like this.
Isn't this true of any code though? How is CSS class naming any different than the naming of types and functions? It's easier to read and understand because it's an abstraction.
Something like...
<div class="button button-primary">
...isn't going to confuse anyone. I believe tailwind is hard to read because it's basically just inlining everything tersely with very little abstraction at all.
Yeah but that is the easiest example imaginable. The problem is not a button class its the card-left-wrapper-container class that you have to use to style something the right way.
It basically boils down to naming things for me. The author says it's a good thing. I don't think so. Most of the time in plain CSS we have to come up with arbitrary names, that introduce confusion and bugs later on.
Utility classes, while sometimes cumbersome to read, always state their intent.
What's the tailwind equivalent of `card-left-wrapper-container`? I imagine it's 200 characters wide.
Based on the name I'm going to assume that the class is used on container for a layout with cards on the left.
Utility classes don't state their intent they state their literal contents. If the intent is to be a button or be a wrapper-container then that's in a well conceived class name.
> Most of the time in plain CSS we have to come up with arbitrary names, that introduce confusion and bugs later on.
If the names are arbitrary then of course have problems! If you code and made up arbitrary names for functions you'd also have problems. The point of the name is to add clarity and abstract out details I don't need to know. I don't need to know that buttons have a certain padding, margin, etc when I'm placing them on a form. And I don't need to know everywhere they are placed when I style them.
> Based on the name I'm going to assume that the class is used on container for a layout with cards on the left.
That's funny my intention was to name a wrapper around a container inside of card that is usually used on the left side. But of course we had different contexts in mind and a lot of these issues can be sorted out by coding conventions.
The thing is I was never able to wrap my head around the whole separation of concerns thing, when it comes to HTML, CSS and JS. I think that is because I come from a mobile dev background where we always had some kind of markup (or just plain code) which described the elements and how they looked. The structure of the UI and the styling were always co-located.
Coming to the web I was very confused of why you would want to separate both of them. And in my opinion we can see that change not only in TailwindCSS, Tachyon or ChakraUI but also in component based JS frameworks as well. Everything is about colocation these days, which makes it much easier to reason about what is going on in this small, little, pocket of code in my application.
You can create components by aggregating the utility classes in tailwind. In fact, the documentation recommends this approach for production[1]. So if you want your "button" class, you can have your "button" class.
The reason tailwindcss has so many proponents is arguably because of its compositional design, but it's paradoxically not one of the first things people seem to talk about when they're discussing tailwind. They fixate on its utility-first design. I think this does it a significant disservice.
It’s more about using established and documented systems vs creating new ones (where you probably don’t have documentation). Even if you do have a home grown solution that is as well documented as tailwind, you are still at a loss because nobody will be familiar with it already.
Yeah I disagree with this. The point of writing code is create new systems. We have literally dozens of applications at my company all with the same look and feel. We, of course, created a new system that defines that look and feel. Just like we create classes, and methods, and components to maintain that. Ignoring the power of CSS to abstract style is a waste of it's potential.
Now that's not to say we don't use established libraries for CSS. But we definitely add our classes and add our customization.
I don’t mean to never create systems, I never said that, did it come across as me implying this? To explicit state my intent, it’s that you should strive to create as few new systems as necessary, but you’re very obviously going to need to create SOMETHING...?
I guess I don't understand your reply. This is a critique of tailwind and the best you can say about it is that it's an existing documented system somebody else might know? I love standards, there are so many to choose from, but on the face of it tailwind doesn't seem like the best standard to choose.
In places where I might find tailwind appropriate, I could use just the even more common standard of bare CSS properties.
The author lost me with "Tailwind is bloated." If it's bloated, you're doing it wrong. One of the main benefits is that you can run a command that creates a custom CSS file that only include the classes you need.
...and it's explicitly mentioned in the manual, which makes me wonder, how someone quoting it (and thus pretends that has read it), missed that part. Most points are pure FUD imo, except the one talking about vertical space, and I believe it's exaggerated.
I think the author is arguing for using something like styled-jsx, which is the same as vue SFC styles afaik. That stays fairly manageable and readable as well.
But it also is as “visually noisy” as tailwind. So it fails at his first point.
Also the tailwind is bloated is disingenuous given you just remove the unused classes as Pty of your build.
Bad faith points all around, maybe except the obscure naming in tailwind. But alternatives like Hucssley solve this (name the properties the same as their css counterparts)
This seems like an appeal to authority or popularity. While we're at it, might as well just pick the most popular library without further thought, because you couldn't possibly make a better choice, and one that everyone chooses must be intrinsically better.
If you're going to offer "criticism like this", at least have something more to go on.
It's not that ambitious to find a more readable solution, if a popular choice seems flawed. That's just a single hurdle to overcome.
"If you can suppress the urge to retch long enough to give it a chance, I really think you’ll wonder how you ever worked with CSS any other way.” - Adam Wathan
The advantage of Tailwind [1] is very subtle over the short term (such as not having to constantly context switch between HTML & CSS files), but dramatically impactful over the long term.
Both in terms of time-savings, as well as code quality and ability to work with others quickly.
It really is something that you must earnestly try to gain an appreciation for.
My initial reaction was the same as the authors when I first came across it. Actually using it on a real life project changed my mind.
I wanted to like Tailwind and, I tried to tolerate it for a few months. To me, it always felt like a less opinionated Bootstrap, but arguably a lot more to learn. The same approach of having to remember class names and syntax is no different than Bootstrap. The differentiator of course, is Tailwind has better tooling support and feels less static, but it's still quite a convoluted beast to wrap your head around.
There does come a time when Tailwind starts to click, you've memorised some of the class names and you get a feel for it. But, I still found myself consulting the documentation to do things "the right way" ultimately spending hours reading documentation, when I could have written plain old CSS. The maintainability aspect in the long-run is the selling point of a solution like Tailwind. CSS without some semblance of order can wreak havoc on a codebase.
These days I am using plain old CSS on a component level inside of Aurelia 2. My components are Web Components utilising Shadow DOM features which scope my styles to the component, but also using Constructable Stylesheets to reuse styles throughout my app. In combination with CSS Variables and Shadow Parts, it's an incredibly powerful workflow that takes a lot of the pain of CSS out of development, it's closer to the metal and feels way nicer.
Hello! I've been trying to adopt Web Components and have had limited success specifically because (since these are internal components) I want to use my application styles, but can't share them across the shadow dom.
Do you have a good writeup or example on the way you're working? I'm googling Constructable Stylesheets, but would love any other pointers, because what you're doing sounds like exactly what I've been wanting to do.
Edit: I see Constructable Stylesheets are Chrome-only. Unfortunately that's a deal-breaker for me :/
Valid points but it's still ultimately down to personal preference and I happen to really like Tailwind. Some people get into this mindset that a project simply shouldn't exist because they, or someone else, writes about why it's bad.
Also filesize isn't as big of an issue that the author makes it out to be.
I've seen that happen, and I sincerely HOPE that folks heed this guy's advice, read the words written by Tailwind's creator, and try and understand the problem it's trying to solve. While I can agree that folks do tend to read negative things on the internet and then turn around and say, "see, I heard it was bad, don't use it", I also like the freedom of this guy to break out of the cargo-culting and say, "nope... this is why I don't like it". It gives me some things to pay attention to when I'm auditioning new libraries/frameworks/etc.
I haven't actually started using Tailwind yet, but I really disagreed with the first point:
> 1. Tailwind Makes Your Code Difficult to Read
...
> First, like Bootstrap, it’s semantically obscure because all of its class names are awkward abbreviations
...
> I would rather look at some CSS that has padding: 0.25rem or margin: 0.5rem instead of trying to mentally map Tailwind’s p-1 or m-2 to their CSS equivalents.
Please the latter is so much easier for me to read, and can (hopefully) be remapped from rem to px in one place, or to use increments of .5 instead of .25, which avoids manually changing potentially hundreds of selectors. Furthermore, using conventions for these kinds of class names makes the knowledge transferrable to another project without having to relearn/rewrite all of these.
> Another reason why Tailwind is so hard to read is because it requires you to pan your eyes horizontally rather than vertically. ... When you string a bunch of class names together, you get markup that looks like this
OK, I get that this could be an issue if you're writing markup by hand, but for a large project this seems like a terrible idea. If you're over in JSX-land (or any templating, really), you'd have an array/set for classNames somewhere, and can just join(' ') it. If for some reason you need to have 50 classes, sure, line-separate them. In many (most?) situations you'd want to construct that array/set programmatically anyway, and encapsulate tightly-coupled display logic in smaller building blocks
I do disagree with a lot of points in this. Tailwind is noisy, and sure its not a silver bullet but it removes one thing from out todo list: css architecture. We are really bad at this, esp. naming stuff. With tailwind we are just getting things done and it looks great.
Recommending jsx styles has at least the same amount of shortcomings as tailwind, the whole post feels like „i dont like and you shouldnt either, because what i use is obviously better.“ :shrug:
Especially the responsive modifiers are a huge enabler. We are actually several month in the making of a very specialized mobile website which is gonna be released as an android and a ios app. Recently we are asked to add a desktop version. I was really concerned about our given deadline and said to the client, it would be possible but would probably take one or two weeks to develop. After telling my colleague that we have to make an desktop version out of the app, we were both concerned. But it turns out that after one day in the making, we did have a fairly good looking desktop version which the client really liked.
I am pretty sure that with plain old css and our poor architecture we wouldnt be able to deliver in time.
Admitting that the point of vendor lock in I do feel and did not think about that long But compared to bootstrap with custom styles applied I pretty much have the same situation i guess
Taiwind CSS is how you get incoherent overall design. Each element is customized to "look" nice but there is no overall architecture and design system. Padding here and padding there, this bold and that bold - visually tuning the entire page to look nice, but lacks a level of design coherency that is achieved best with a classic CSS based approach. You can do it with Taiwind to "remember" standard padding/spacing and Tachyons does it better than Tailwind, but I personally prefer the classic method even though its not as immediate as Tailwind classes inline with HTML.
People are allured by the rapid prototyping aspects of Tailwind which is the main bait. It's pretty fast to see results immediately without openining the css file.
This seems directly in opposition to my experience of Tailwind. Assuming you are using some sort of component based setup, like React, Tailwind mercilessly enforces consistency. You can't just use padding-left: 10px in one place and padding-left: 12px in another. Same goes for font-sizes and everything else. You're locked into the design system to such a degree that its a lot of work to deviate from the standards. Couple this with components that ensure the proper reuse of style and markup and everything is consistent everywhere.
If you are working on more of document project where markup reuse through components or partials isn't available then I could totally see your design elements like buttons or cards becoming inconsistent but your spacing, font-sizes, z-indexes etc. will still follow the system.
People are allured by the rapid prototyping aspects of Tailwind which is the main bait. It's pretty fast to see results immediately without openining the css file.
This an interesting psychological point to discuss IMO, we get lured to things that feel "fast" but actually aren't.
That sounds just like Duolingo (it feels like you're making progress because you're getting better at the things that it's testing, but unless you try to participate in real conversations in the language, you're not making progress in an actually useful direction)
> This an interesting psychological point to discuss IMO, we get lured to things that feel "fast" but actually aren't.
It's not so much “feels fast but actually aren’t” as “fast onramp that makes downstream maintenance slow”.
That people tend to be bad at balancing downstream costs against current benefits is well known, and that's even outside the context of business situations where the cost is attached to a role that decision-makers may expect to be out of before the cost is realized, and outside of social contexts like speed-of-this-iteration-focussed development methodologies that structurally encourage discounting future costs.
It is actually fast though. Just doesn't produce coherent design over time and creates a huge mess where design langauge is intertwined in symantic layout.
Hey, wasn't that the original intent of HTML+CSS? To isolate markup and design?
When I started in a project that made use of tailwind, I initially exactly felt the points the author is making here: The HTML is a mess, dev-tools don't play as nice, why would anyone like this?
Unlike the author though, I have grown to love it - not having to look at two files to understand what's going on (html/css) really felt like a big boon, especially for "trivial" UIs that just need a bit of flexbox, css-breakpoints and a margin here and there to get going. For more complex stuff, falling back on custom classes is still perfectly fine.
Also, the "html becomes a mess" argument was only an initial issue. Once you get used to the tailwind-classes, most of it becomes fairly readable - the examples of the author are, in my opinion, just as unreadable in css, especially if you're not a design-oriented css-geek (like myself).
The big "aha moment" with dev tools for me was realizing that instead of interacting mainly with the style editor, you transition to interacting primarily with the classname editor with tailwind. Then dev tools is your friend again.
>not having to look at two files to understand what's going on (html/css) really felt like a big boon,
If I am currently creating the html and the css I don't have to look at both to understand what's going on. I only have to look at both if I am coming into some html and css that was created a while ago.
If I have to understand the html and css that was created a while ago and how it all relates I don't do it by looking at different files - I do it by opening up the browser and inspecting.
I suppose you have a different way of doing it that I have difficulty envisioning.
- yeah, I like having the whole project's code in one big index.php file. No context switching, no need to go through dozens of files (controllers, models, etc.) to understand what the system is about. No semantic naming at all. My productivity is high!
The majority of the comments here that praise Tailwind seem to be from people who are actually not " 100% frontenders", but perhaps "fullstack devs" or even "backend devs" that have to touch HTML/CSS from time to time. It's understandable that the practicality of Tailwind attracts people who work occasionally on the frontend.
I hated Tailwind until I went whole hog on a project. There are so many nice little benefits to it, and those compound. Maintenance is a huge win. I haven’t accidentally broken styles once since switching to Tailwind. The VS Code tooling is great. The workflow is great. The reduced context switching is great. Using it with Preact is great, and my app’s bundle size is still smaller than just the dependencies on most React projects I’ve worked on, so I think the bloat is overblown.
I’m sure there are downsides, but the upsides so far seem to dramatically outweigh the downsides.
I think it's a fairly compelling article. There is a lot of hand-waving around tailwind; I have never seen so many people collectively play the "I can't articulate why it's good, but after using it for a while I can never go back!!" card about a technology before. But I think author hit the nail on the head about the benefit of tailwind: rapid prototyping, but that's about it. I will use tailwind for my next small project. But I can't deny that it is indeed technical debt, albeit one that I have grown to indulge.
My team maintains around 200 websites on behalf of a design agency. Performance isn't important, and these clients aren't paying much.
Let's say a client wants to add a custom page, with some custom design.
Where do I add that? Into the global CSS, where now it needs to be maintained? Do I use a body#custom_page selector before everything? I've got elements that I now want to override only on this page. The easiest way is using inline CSS, except I can't inline responsive and pseudo-states. Updating the 5000 line CSS file with a bunch of classes under a body#custom_page selector is hard to maintain.
Tailwind solves this problem, by effectively allowing me to use inline styles even for responsive and pseudo-states, and simple variables.
CSS is effectively global state. You make a change on one bit of CSS, it can affect any part of the website, so you have to know about the whole website before making changes. And that's impossible when you maintain 100s of websites, especially when budgets are small.
I can see why Tailwind isn't helpful in a large company maintaining its own large website. But for small teams managing lots of different websites, it's fantastic. It allows you to localise and isolate the effects of CSS.
I maintain something much smaller and I'm trying to understand the various use cases, so please bear with me.
What's the problem with the #custom_page selector? If inline styles have oddities, why not keep it in separate css files, one per custom page? That would seem to precisely match the cascading style CSS is supposed to handle in the first place.
That's a lot of files if you've got 200 related-but-slightly-customized pages, but it tracks the organization of the project as a whole, no?
> What's the problem with the #custom_page selector?
This is exactly what we've done for years, but with tight deadlines, small budgets, long-running projects take on all sorts of crufty technical debt. Maybe I change a value in "special_page.css" and suddenly the homepage breaks.
Tailwind lets us isolate that cruft to where it matters.
It's not a silver bullet, but it's helped immensely. Initially, I thought it might just be "new broom syndrome", but after a year of using it, I'm still in love in a way that I haven't been since the launch of jQuery.
> Maybe I change a value in "special_page.css" and suddenly the homepage break
I'm sympathetic to this problem, having suffered through it plenty of times, but it seems like a scoping problem, and an entire library of specific functional CSS classes doesn't seem particularly well-matched to a scoping problem.
I believe everybody who says "Tailwind saved me the of work matching up CSS that was file-separated from its markup AND thinking about selector scope." And I guess this is one way to do it, but the overhead of a comprehensive property-to-class mapping seems inefficient and it's really not clear to me advantages it has over the method of the author of the article described, which also keeps markup and css in the same source file and manages scoping issues.
Yeah, the root cause is a combination of designers and sales collaborating to promise the client something out of their price bracket. If I could convince clients to pay me without that collaboration, then I'd run my own agency and be super-rich. Instead, we take on technical debt, and Tailwind lets us manage that debt more easily.
One of these days I'm gonna have to try it. Every time I read it, a lot of things strike me as Wrong (special preprocessor, obfuscated names, bypassing the "intended" way to use CSS). But so many people say "I love it and use it for everything" that it's worth investigating. (I had similar complaints about React and it's practically indispensable now.)
in a rare case where CSS actually seems to have an intent rather than throwing spaghetti at a wall to see what sticks
If the page is "special", then it simply gets a special stylesheet. I don't understand how people get so much wrong about CSS when it's really such a simple tool. My best guess is that many developers are so deeply lost in the pit of OOP that they want to apply this thinking to HTML, which just doesn't work.
You're probably right about why some people find it easier than others. As a predominantly backend dev who has to maintain frontend systems, I'm a fan of anything (such as Tailwind) that helps me do that more effectively. I'm not going to refuse to use it out of a sense of pride that I "should be able to do this in CSS myself".
Like many discussions, Tailwind is a topic on which some of us are guilty of not stepping back and realising that others have different views mostly due to their background and the tools that they've used, and that those views are totally valid.
For example, I also don't like Tailwind (or, for that matter, Tachyons or any of the similar tools). I find it absolutely infuriating to work on a site that uses it, it is a massive drag on my productivity, and offers quite literally nothing that I want.
But here's the thing – I was a front-end specialist for years. I know how to write CSS and Sass, how to build UIs from them, and I have an established set of patterns and helpers for doing so. I used to be a graphic designer too, so doing things like building an application-specific design system is my bread-and-butter. For me, Tailwind is a massive distracting abstraction on top of a thing that I'm already completely comfortable using.
Other people aren't necessarily in the same position. It takes a lot of time and work to start thinking in terms of the way that styling works on the web, and CSS is pretty different to many of the languages and tools that developers are used to. If you're a back-end developer who is primarily interesting in implementing a straightforward and functional UI for something, then investing lots of time in the quite different skill set of front-end styling probably doesn't offer a good return. So there are sets of tools out there which make it easy to write simple, organised, and maintainable sets of styles, without having to get right into the weeds.
Of course as always YYMV and you might be a CSS expert who loves the consistency of this kind of framework. But I'd definitely back up the idea I've seen some other people mention – there's no obvious right or wrong, or objectively correct answer.
You're right that there is no obvious right or wrong, but I don't think it's a matter of background either. For example, I have a similar background and think that the "old" way of doing things is an over-abstracted waste of time.
I spent many years doing frontends with CSS, then Less, Sass, and I have used all of the popular methodologies at some point or another. I am very comfortable building things that way, and it would probably be my preference, all things being equal.
However, developing with Tailwind is just plain faster than the other methodologies. And it's easier to adjust components in production. When it comes down to it, those are two areas that Tailwind excels in, and high-abstraction CSS methodologies (despite their other merits) do not.
I don't understand how Tailwind would make writing CSS easier if you're not an expert. The complexity of CSS is in learning how the layout algorithm works, and how to implement common UI patterns. You're still writing exactly the same CSS rules in Tailwind, just with a different syntax. The complexity remains exactly the same.
I'd argue a lot of the complexity in CSS comes from how people typically write it: lumping a bunch of properties into "semantic" classes, then trying to juggle how those all cascade and interact when nested within other such classes. I think we've all lost the will to live trying to "undo" a style cascaded from an element's great-great-grandparent.
Of course, you don't have to do that—you could write your CSS classes as ultra-low specificity classes that each only target one property...but I think you'll find that's what Tailwind is :)
Ive been doing CSS in every flavor imaginable for twenty years now. Until Tailwind came along it was always my least favorite part of coding for the web. Tailwind eliminates all that accidental coupling that eventually turns every CSS codebase into a tar pit nobody dares to clean up.
>This means that you have to first learn Tailwind’s specific syntax before you can fluently string its utility classes together to achieve powerful results.
A pretty strong one. If I'm maintaining a project, I really do not want to spend my time learning some random DSL made up of obscure class names with abbreviated letters and numbers just to change the padding on a div. The component based approach is infinitely more maintainable. Things like Tailwind are fine for quickly prototyping something if you can't be bothered with design or styling at the time. But long term they are a maintenance nightmare.
I think it's the exact opposite. Having maintained some else's CSS on dozens of projects, Tailwind is soo easy to keep maintained.
You don't have to learn some else's idea of what CSS belongs to a component and how they structured it. You just go into the HTML, add or remove a couple of tokens and you can be sure yoyu didn't break anything else.
Once you've learned it - which doesn't take very long - it scales to other projects. You don't have to relearn - again - what someone else thought would make a good CSS abstraction for their UI.
I second that. The majority of web projects I've seen had class names scattered all over different files and it was always a nightmare to make significant changes. You don't have this exact problem with Tailwind.
Component based approach is widely addopted and proven by big and small players in the industry (I'm not even gonna name drop because it's everyone), and practically all existing frontend frameworks, it's not really debatable at this point. What is debadable is how you implement components, which probably was why yours was unmaintainable.
I believe parent is not really talking about React/Vue/Angular components, but rather about CSS components.
Framework components are indeed industry standard, and I'd argue that Tailwind (and Atomic CSS in general) also works better with them.
But CSS components (the alternative to Tailwind) are a hot mess. There are lots of methodologies, some of them are very complex, but even the straightforward ones like BEM are very error-prone when used by developers who haven't been using it for long.
same thing, aren't css components just components that are purely stylistic?
I have used the trio styled-components, typescript, react which results in highly reusable, self documented UI primitives. You write css not some made up language and you map your modifiers (in BEM lingo) to react props which is then type checked by typescript. You can also use all the existing css tooling like sass mixins etc, not that you're gonna need them.
It's not really the same thing, expecially if we're talking about the problems.
If you're directly coupling CSS components to React components, then you won't really see the issues me and GP are talking about. Names can be inconsistent because markup is centralised, it will be rarer to see overrides, people will be more reluctant to change it to fix one part of the website and then breaking all others... etc.
Big websites have been built in all kinds of technologies including PHP and Cold Fusion. That's not the question. The question is how do the utility and component based approaches compare and having worked extensively in both I'll take the utility approach every time.
If you want to change the padding in a project that's using Tailwind you only need to look for classes that begin with `p` followed by a letter for a side or x and y for an axis (same is true for margins). Those are by far the most cryptic classnames and by the time you finish reading this sentence you got it.
In a project where you have to name everything semantically you don't know where the hell the padding is going to be.
It's amazing for long term maintainability and quick prototyping. There is a lot of value in classes that does one thing well.
Been wrinting CSS for 15 years, switched to Tailwind 2 years ago, just for reference.
I had never used Tailwind CSS, but on my side project I picked it up very quickly. The docs are good and it doesn't deviate too much from CSS frameworks like Bootstrap.
I tried the 'functional CSS' approach a few years ago and whilst at first I found it pleasurable to use, I ultimately grew to hate it. The biggest pain-points for me were exposed when returning to older code -- parsing the intertertwined mix of utiltiy class names and html added a level of overhead that I didn't have before. Additionally, later on in projects I'd encouter more edge cases where I need to provide bespoke styling for certain elements. As soon as you need to mix functional with traditional CSS I found the overhead to increase further.
That is my biggest pet peeve, there are no uniquely identifying class names anymore so in a big enough project it can end up really hard to find what is generating the HTML you need to change.
It's part of an overall code quality attribute I refer to as "discoverability" which is tied very closely to clean organisation and maintainability. Can't maintain something quickly if it takes 10 minutes to reverse engineer the code and find it.
Unique identifiers are something that should be added separately.
It's not just debugging: If you're doing any kind of testing on the UI you already need class or data attributes to identify the components you're using, otherwise you test becomes coupled to the structure, or worse: to the styling.
The difference of Tailwind to other methodologies is that the Tailwind classes are used exclusively for layout.
I actually went through a phase after realising this of outputing strings of utility classes to named variables to essentially emultate the benfits of CSS class names. My next realisation was that I might as well just be writing plain CSS.
In the end I recognised that the things I actually liked about functional CSS were more or less the same things I liked about CSS-in-JS: colocating styles and markup (albeit with blocks of css rather than utility classes) and the approximate scoping of styles. I ended up writing a build tool that fascilitates this outside of React / JS.
If you're using a frontend framework, sure, you can use React devtools or equivalents.
I think tailwind in React does make a lot of sense, but I think there are even more simple solutions to use inside React that solve the same problems but with normal CSS and none of the extra tooling and config of Tailwind.
You can think of tailwind like a higher level language for CSS, since you are writing inline CSS again just with more concise attributes. With that being it's only real advantage in my opinion, I didn't think it was worth learning a whole new dialect just to avoid a few lines of CSS. CSS variables can be solved trivially with an imported JS object, so the config file as well adds a lot of minutiae knowledge without delivering that much more benefit.
At any rate, it is for some people and not others. I'm not going to try too hard to objectively prove why I don't like it, it just adds a lot of tooling overhead while not really solving enough problems for me.
Utility classes are good, don't worry about that. Utility classes are a required part of any good CSS system.
Programming with only utility classes, and patterns like OOCSS and BEM are bad, and we've stopped using these for literally decades.
The more important question is how do these libraries work under the hood, which is both little understood and rarely included in analysis. Breaking out CSS files is critical, any CSS created and inserted by Javascript is unforgivable in production. Focusing on what the libraries do in production is the key. And if your tool needs some special DSL to use native CSS features like @keyframes, don't use that tool. Period.
The author is right in that CSS is 100% a solved problem, and the answer is component scoped CSS with some global utility classes (which can come from Bootstrap or wherever if you choose to use such a framework). There's nothing better, it solves every need, and doesn't come with any of the baggage of other systems.
We often talk about the rule of three in software development. The idea is that you don’t start looking for abstractions until you have at least three instances where that abstraction will be useful. The problem with component based or semantic CSS is that it forces you to define abstractions for everything up front even if n=1.
The beauty of Tailwind is that you can still define abstractions when they are needed and pay the price of using abstractions but you can also handle the many one offs every site has in a much cleaner and more direct way.
Tailwind brings with it the same issues that css-in-js does: the inability to just reload css curing the development cycle. When working with css (or a language that complies to css), any changes to the style are pushed to the browser without a page refresh. With tailwind and css-in-js, changes to style require changes to js/html and therefore require an entire page reload which both slows down my feedback loop and breaks any state I had established in my test app.
> With tailwind and css-in-js, changes to style require changes to js/html and therefore require an entire page reload
ah!! I was wondering why HMR wasn't working like I remembered the first time I used React. I think the first time I picked up React I used plain CSS, and the CSS would change on the page without reloading. Now I'm using tailwind and material-ui and thought HMR was just busted.
I like tailwind but it doesn't play well with material-ui. Material components always take precedence which is super annoying. I might just end up canning tailwind.
> But I can’t imagine that it’s possible to create a tool that does the reverse: converting Tailwind to semantic HTML and CSS. The only thing you could realistically convert Tailwind to is some other utility framework (e.g., Bootstrap) that locks you in with its own syntax and class names.
I don't understand what is impossible about this. A standard tree walker and a GUI tool to define the individual components will suffice. Or to make things simpler, have a command line tool that takes in the CSS selector/XPath of the desired tag/component and generate the relevant CSS. There are already browser extensions that can do this. Also, nothing is stopping you from writing semantic HTML. Vanilla Tailwind is an (almost) one-to-one bijective mapping to CSS. It does not define your HTML unless you are using prebuilt components.
Converting non-semantic HTML names/classes to semantic HTML names/classes would require knowing the semantics which is really, really, really, hard. You can probably turn it into "big red button" easily but knowing that means "cancel-account" is hard.
But the semantic HTML part is absolutely not related to Tailwind. Aside from the component library, Tailwind is a CSS framework that operates (mostly) on the class property of each HTML tag. The semanticness of HTML is defined by the tag itself and additional properties like ARIA, data-*, and various other identifiers like those from the RDF schema standards. It is an issue completely orthogonal to atomic CSS.
> I don't understand what is impossible about this.
Agree, and as someone who's done these conversions both ways I wanted to just say that you don't have to use complex tools to do what you're describing really. Those things are definitely in my toolbox, but simply just going by-hand and duplicating applicable styles from one site to the other with Chrome/Firefox devtools is a breeze.
I say this as a developer who embraces/studies CSS
Semantic vs utility classes is a religious war that will outlive us all, so I'll try to stick to my personal experience and not get too far into the weeds.
With that said: this resonates strongly with my experience using utility classes (Bootstrap, not Tailwind, but I think it's close enough for these purposes). On the giant front-end codebase that I used to manage - which didn't use any CSS libraries or utility classes - here are some things I learned:
- It's okay to have semantic classes and also bundle commonly repeated styles under reusable classes. Most of our classes were component-specific, but we had maybe four or five cases where a particular set of multiple(!) CSS properties were repeated in all sorts of different semantic contexts, so we encapsulated those as "utility" classes. However, when it was just one property getting used frequently...
- We learned that inline styles aren't the devil. It's perfectly fine to do `style="display:flex; margin-left:1em;"`. The only disadvantage this has compared to utility classes is brevity. And in exchange, it's much more readable and carries zero bloat or lock-in. The verbosity also encourages you to move styles to a more meaningful place once the amount reaches a certain threshold.
- For consistency in styling/spacing/branding: just use CSS variables. Preprocessor variables work fine, as do native custom-properties. `margin-left: var(--m-4);` works just as well as `class="ml-4"`, with the added benefit that it can be used equally well inline or in a stylesheet (and, again, no bloat or lock-in). Another interesting benefit is that that value can be reused and assigned to other properties; for example, maybe in one spot you want to `padding-left: var(--m-4);`.
- Unpopular opinion: your HTML and CSS aren't really separate concerns in most cases. Sometimes you can find repetition that can be factored out, and if so that's great, but the CSS that controls your layout is and always will be intimately tied to the DOM structure it's targeting. Given this, in my experience, you're much better off having hyper-specific class names (most of the time!) and, if you find it helpful, some sort of componentization/scoping system to make sure they stay hyper-specific and don't leak (I didn't find that we needed the latter, though only because we followed very strong conventions).
That's just my two cents. In my decade of writing CSS I've come out against utility classes as a formal methodology, though I'm also very comfortable hand-writing CSS and I've mostly worked at small companies, so those factors and others may bias my opinion.
One thing I rarely see mentioned in discussions about Tailwind is inheritance - one of CSS's biggest strengths but also biggest weaknesses. With Tailwind, you never even have to think about inheritance ever again! No class can ever be accidentally overridden by another added elsewhere. This is a huge win for stability when working in bigger teams.
Sure, scoped CSS also handles this but most developers are not building JavaScript SPAs. They're building monolith applications or WordPress/Magento/Craft/whatever themes where a handful of stylesheets are included via a <link> tag.
I don't feel like it does vendor lock-in. It only really locks you into using utility CSS, but you can "eject" at any time by throwing out the framework and keeping your compiled file with utility classes.
And then... you'll keep two wildly different CSS styles for the same project? That doesn't seem reasonable.
Vendor lock-in doesn't mean that you can't get out at all, just that it has significant cost. Maintaining both Tailwind and another CSS framework/philosophy/classes in the same project has a significant cost.
Yes, but this is the same kind of cost as, say, switching from an OO to a functional design, and we don't normally refer to "choosing to use OO" as "vendor lock-in". This phrase is normally reserved for use when there is a vendor that one must pay in order to continue to use a service, not merely cases where there is some difficulty or annoyance involved in changing something.
I completely agree with the maker's point that class names are the bane of CSS design. However, styled components have been amazing in this regard. I've tried a lot of solutions over the past 8 years and this is my favorite by far. No extra crap, but you still get reusability and the syntax is like plain CSS. I tried JSS but I can't get over defining styles as JS objects, not to mention made Typescript slow to a crawl.
Well I agree on the premise to some extent, but I don't feel like all the examples and points are as high impact as others. For example, I don't think that styled-jsx is really the solution to the problem - writing the stylesheets inside JSX? Sounds.. strange.
From what I can see, Tailwind doesn't offer a solution to the div-soup HTML at times becomes. When I look at five or more nested divs I kinda forget what I'm even looking at. Having semantic names is crucial in maintaining a layer of abstraction that helps to map the HTML inside your brain as entities with specific purposes. I myself use JSX and name my elements as Container, ButtonGroup or TooltipWrapper for example.
The other problem I see are the conditional class names - how does Tailwind deal with them? Do you write if-else class names? Doesn't seem very clean. I myself use styled components where I add properties, such as visible={isVisible}, and resolve them inside the stylesheet where the value matters.
The benefits of Tailwind, however, seem also evident to me as abstracting away CSS into much smaller number of utility CSS classes does appear to be a very quick way to make decent layouts. It's just that having done plenty of CSS/SCSS I don't find it too time-consuming to write the CSS myself. And also because of the previous points.
I ended up creating my own utility classes for projects instead of adopting Tailwinds.
My issue with Tailwinds from a design standpoint is that it allows for too many combinations, which is the issue with plain CSS. Having less choices makes things more consistent and IMO easier to read.
For example, a font style in our project includes the family, weight, line-height, alignment, and size in one class. This is called something like `Font16RR`. Responsive sizing is handled in the class itself (so, it may be 20pt on large screens, even though it is called "16").
We also have utilities for a small set of spacers, margins, colors, and layouts.
These are defined in parallel with the UI designer, so we both call them the same thing and we agree it's a "big deal" to add a new one. This has reduced the number of styles in a large legacy app dramatically, making everything look much more consistent.
This has the added benefit of being very easy to provide different themes which was a requirement of the project. I admit that this system requires other front end developers to either 1) Internalize the design system or 2) Receive specific mockups and copy them verbatim.
Would love to hear the perspective of anyone who has worked on whitelabel software and had to manage multiple themes and/or worked with very strict design systems with Tailwinds.
> Because every new class name that you introduce could have potentially hundreds of property-value combinations, and that translates to more compiled CSS—which, of course, means a larger network request, and potentially slower performance.
After PurgeCSS you can end up with a 15kb CSS bundled payload even before gzip for a decently sized site. That's so much smaller than most other CSS libraries because Tailwind is very purge friendly.
Unlike other methods I’ve seen Tailwind based projects result in very small CSS payloads that tend to grow asymptotically over time instead of getting bigger and more bloated over time as people keep adding new “semantic” classes.
And purge css is not some "other thing" you have to go get to use tailwind effectively, it's built in! You don't need webpack in the mix or whatever, you just need a couple of lines in your tailwind config.
In real life, tailwind produces the smallest dist files of anything I've used just because the built in treeshaking thing is just effortless and works so well.
(Clearly this is my least favorite "I don't like tailwind" gripe lol)
Came looking for this comment. 100% agreed, and it seems like the author didn't even try?
My site https://www.listenaddict.com/ is 5.6kg for all the core/layout, and then another 1.6kg for the color theme (I have 12x themes and they're all separate, so the user only has to load one of them).
How about just giving CSS a tag to vertically and/or horizontally center multiline text in a box, without needing constructions involving multiple elements. Preferably with a simple name like "center" or "middle", though unfortunately those two names are already taken up by things that do not actually put the thing in the center or middle.
Original HTML could do it in table cells. What's taking CSS so long.
It sure doesn't help that there are multiple "easy" ways to do it. A sibling content mentions flexbox. There's another with CSS transforms.
CSS accumulates techniques, each one intended to compensate for defects with the other -- and they interact in obscure ways. Googling will always turn up recommendations for each. You end up with Perl-like "There Is More Than One Way To Do It" -- and you have to know all of them if you want to actually do anything.
Is `display: table` a css feature made for centering things? No?
Not a fan of tailwind, but whoever thinks that is simple misunderstood the meaning of the word, it's not about the number of characters you have to type.
Two of those lines exist to handle each axis separately, the first is to define the layout mode you are using. It doesn't get much simpler while still maintaining a fine level of control over each aspect of the layout. I don't buy that it has to be "better" than this.
Justify content and Align items operate on the Main axis and the Cross axis respectively. By default this would be the horizontal and vertical. Because of the flexibility of the layout system you can tell it to distribute the main axis vertically instead (flex-direction: column) which would make the cross access horizontal. There is a consistent logic to this which affords a lot of power when creating layouts.
The current layout system is designed with language (and content) direction preferences in mind. Could you expand on what you think an ideal layout system would be? I'd be interested to see what an alternative would look like with the same considerations.
A great an opinion, which I once held. But when I looked deeply I only saw benefits.
I see tailwind as a damn cheat (a good thing), a hyper productivity tool throwing away all the what we learned as 'correct', and just get things done with escape hatches to fallback.
- Rapid prototyping with tailwiwnd
- Making component frameworks like bootstap? Just use tailwind sass with helpers. You can use a sass approach with including the helpers so you dont polute your DOM.
- it is easy to remember and guess which increases velocity. p-1/2 etc.. m-1 p-2 etc etc. Conventions make sense!
- Bloat can be solved with purge
- Refactoring easy easy if you abstract it away in sass so you can make global style changes.
- Protyping is easy, and you can then move it towards a component framework once you've done wiggling around and changing your stuff.
- I find css in components hard and painful personally also makes doing broad style refactors a bit more difficult.
- I also use css for email and other simple landing pages that dont require html components or react/webcomponents or whatever.
I find this a great addition to my life. Its a darn sharp knife, up to you what you do with it.
Bloat can be _partially_ solved with purge. You still end up with a somewhat larger HTML file because of all the extra class names you have to write. To me Tailwind is worth the extra bytes, which, after all, probably doesn't represent that much of an increase in file size.
For sure but and even if you find that too much you can just use the helpers in SASS and you can just write your plain old classes and then tailwind is just another sass framework.
On the other hand, I quite like Tailwind because if I'm looking for a CSS option, it's more discoverable than raw CSS, "text-", "bg-" and so on. It's consistent.
As for 'it makes your code harder to read', I simply write the classes in HTML, then when done, move them to my CSS file via @apply, and my HTML looks the same as it has always done.
The author didn't touch one of the biggest issues of Tailwind. It ignores the Cascade part of CSS.
Even after optimizing Tailwind. You still end up with way more css than you should have. Add all the classes in the HTML and you're sending users a massive amount of data.
What do you do with that snippet when you realize some elements arbitrarily need more or less spacing than others because the designer decided it looks better?
Repeating yourself isn't the end of the world, and on occasion DRY is worse (look up incidental duplication).
And so, his recommendation is to use styled-jsx which is pretty much abandoned (despite of what they say) [1] and not even themselves are using it [2]
I do think css-in-js solutions are good, but also they're a lot more work, and probably better suited for large teams with a shared design system, etc, etc.
Personally, I think Tailwind is great. But I understand some people don't like it and cannot appreciate it because it might not look good seeing many classes and "but this is just inline styles". Ok, not for you. It is still great for some other people.
I used to think like this for a long time, but after using Tailwind on real projects - there is a definite moment when it clicks and you wonder why you've been doing it any other way.
It's funny how the author talks about vendor lock-in (which is kind of a non-issue with tailwind, since you can eject anytime) and then suggests styled-jsx as the better solution.
The problem with this invective is none of the points really stand alone if the first point happens to based on an incomplete understanding. Unfortunately, that seems to be the case here.
Using Tailwind purely at the HTML level is not the only way to use it, and in fact, this is only supposed to be used at the prototyping stage. it's a pretty standard part of the Tailwind workflow to extract class combinations into helpers that can be reused. If utilization doesn't even get to this depth of use of the tool, can one really consider the usage the tool to be anything more than an abuse?
Frankly, Tailwind was a gamechanger for the way I do vanilla CSS. It makes it really fast for me to prototype, straightforward for me to refactor, and I end up with CSS and HTML that is straightforward and easy to maintain. It is what I always wanted Bootstrap to be, which is the Rails of CSS. Now, there are certainly valid critiques to be made of Tailwind, just as there are valid critiques to be made of Rails. But in my opinion, many of those critiques are red herrings that boil down to abuses of a very useful tool. I always have to ask myself in these situations if the problem is the tool itself (if used properly) or an abuse of the tool.
True, before I learned how to use Tailwind and grokked /why/ people used it, I was suspicious and leaned towards the former. But that's exactly why I wanted to force myself to use it and figure out what everyone else was excited about, even if I didn't feel the same.
Of course, once I learned it a little bit, I felt the same way I did about Rails, which is that it's an extremely useful tool for a lot of jobs. It did not get popular by accident, or because "everyone is an idiot" -- it got popular because it solved a very real problem significantly better than its competition.
I would hope the author eventually opens their mind a little bit to try and figure out why that is the case. They just might experience the same a-ha moment that I did.
In my earlier projects I always found myself doing exactly what Tailwind does, manually. As Tailwind does it much more throughly, I'm now 200% productive. I can adjust everything by just stacking classes. For me it's perfect but I can see why some people dislike it.
The authors proposed replacement requires me to be involved with Javascript deeply.
I use Tailwind to style templates that are used for static pages. I don't have JSX components, I don't have javascript at all other than for Tailwind's building...
Tailwind is great. I have quickly been able to create a template that reflows based upon the size of the browser, in a manner I haven't been able to do so before, and all in the same place where I am already defining the HTML. If I were to do it with media queries and have to redefine `.thing` in two different places if I made a change to one I would now have to hunt it across the file to make the change in the other four locations for all of the breakpoints I want, that becomes tiresome quickly.
I asked the author of headwind about this one time, for now what I do is simply use @apply if it's getting a bit unwieldy even if I only use that once place.
Use bem like convention for your css so that all your custom classes are "flattened". See eg. SuitCss naming conventions. Lint with postcss-bem-linter so classes follow PascalCase component names typical in React or Vue. Also lint for a optinal namespace (prefix eg. ais- used in Algolia Search).
Then import tailwind after yours, that way any simple flattened class can be overridden by tailwind utils.
So now you can have component say .ns-MessageBox feature a default text color, or font size or anything, (optinally using @apply in the scss stylesheet) and you can override any good defaults, as well as handle layout & spacing in the template eg.
<div class="ns-MessageBox text-red mb-4">…</div>
Likewise then you can also set a good default stylesheet for plain html headings, lists, etc. Because selector "h2" can be overridden by utility. So your headings lists etc can also have sensible default bottom margins padding and whatnot. You have to look at the design templates to determine good defaults, then you dont need to be so verbose with tw in templates.
Then you can also keep your entire color system in Sass if you prefer, take advantage of Sass functions.
It’s very flexible.
A good ruleof thumb is to use tailwind in templates for all the space around components, main layout and spacing of all individual components. Those are the things that tend to bring really confusing and complicated css selectors with pseudo selectors to target first/last elements, which is hard to maintain, hard to read for other devs, much better handled in templates.
The problem that I have with Tailwind is that it's not that different than using inlined styles but adds a lot of bloat without a path to clean abstractions.
It's similar to inline styles in one way but different in about five or six ways. Putting that to the side, what do you mean by clean abstractions?
With Tailwind, all of your abstractions are explicit; the styles are right there on your component, with a more or less 1:1 correspondence to CSS properties. Everything does what it says it does.
In traditional CSS methodologies, the abstractions are implicit but hidden. The relationships between the stylesheet and markup are still there, but they cannot be understood without knowing both structures intimately.
Which of these is cleaner, and for what purpose? At the end of the day, code is not there to be looked at, it's meant to be deployed and maintained.
The limitation with inline styles is that the moment you need a single variation (hover, responsive, dark mode) you’re forced to move the styles somewhere else. Tailwind solves that, and a bunch of other stuff.
The only thing I really didn't like about tailwind was the danger of changing tailwind.config and the long className lists. I "solved" both of those issues with a simple macro and PostCSS plugin: https://github.com/fleck/class-types.macro#why-use-this-libr...
I tried to use Tailwind to style a project, built in Rails, with server-rendered HTML templating. I found that it was too much work to keep it all straight in vanilla HTML. But I could see Tailwind being a great fit if I started a project using, say, Vue components. In that world, Vue helps remove some of the repetition by hiding it in higher-order components.
I find it good for quick prototyping or personal demo projects but I wouldn't use recommend it for a large project with many contributors.
The trade-off between having messy html for faster development or css-in-js is not worth it for me. I still don't like mixing html (jsx) with javascript. I'm an old-school seperation of code vs concerns.
Large projects with many contributors is exactly where Tailwind shines. It prevents that ever growing pile of intractable mud that every CSS codebase tends to turn into over time.
>"It prevents that ever growing pile of intractable mud that every CSS codebase tends to turn into over time"
This is why the key is not having a seperate CSS codebase. The separation of CSS and JS is just a legacy of web development from the time before component based application development. At most you might need a common source of basic variables like theme colors. But essentially everything else should be scoped within the context of an individual component, and live directly within that component. Huge stylesheets with specific selectors and complicated BEM style class names just aren't necessary anymore.
I’ve built big sites this way too and it’s a small improvement over pure CSS methods but still much less productive and maintainable than the utility approach.
like many others here, I was a bit dubious with tailwind at first, but I've been using it for a year now with vue. I think for me, because I'd often do my CSS in a similar manner where I'd build up utilities, this seemed like a nice standardized and reusable way of what I was doing anyways. It's super fast to do things when you learn it, the optimized css output is tiny, it is really configurable, I find it pretty easy to read and understand what is going on. I understand what is going on with other peoples tailwind projects really easily also.
What is weird, is the author, without irony, uses his vendor lockin to react to argue for better ways to do css? ok.... 1, his examples are super simplisitc and 2 that would actually look really simple in tailwind rather than string injected variables. Which if you have to keep using everywhere is going to make your css super bloated.
I have used Tailwind on multiple large production sites over the years and seen pretty hard core CSS devs learn it. Every time they start off with skepticism. One week in they love it. To address your points,
1. Tailwind Makes Your Code Difficult to Read
Not sure why the styled-jsx examples at the end are easier to read. Tailwind is semantically obscure like any language you don't know is semantically obscure. Also with the intellisese VSCode gives you, learning is super easy.
2. Tailwind Is Vendor Lock-in
Vendor lock-in is a really strong word for what is going on here. Would you say React is vendor lock in because switching to another lib is hard? I worked at a company where we switched all of our CSS modules to Tailwind, and it actually cleaned up the code quite a lot.
3. Tailwind Is Bloated
It's actually the opposite. Large companies use atomic css approaches because it keeps your CSS bundle small. Especially with purgecss, you can get bundle sizes super small. I even saw a company switch from CSS modules to Tailwind to reduce they CSS size for AMP.
4. Tailwind Is an Unnecessary Abstraction
@apply is the equivalent of composing functions together in any other programming language. Also @apply lets you keep using the scales and color palette you set in tailwind.
5. Semantics Is Important. Tailwind Forgoes It.
Naming things is hard. It's a problem in regular programming, and CSS is no different. Needing to name less things makes life easier, especially when you component system name is already descriptive.
6. Tailwind and Dev Tools Don’t Play Nicely
Usually I just click .cls in dev tools and check or uncheck styles as needed. Or if I start typing a style dev tools intellisense helps me.
7. Tailwind Is Still Missing Some Key Features
pseudo elements are being discussed. As for it not being possible because of bloat, see above (PurgeCSS)
The author doesn’t understand value of utilities and composition, regardless of the css framework. Unsurprisingly then, recommends awful css in js approach.
Granted the value of composition is most appreciated when you do the frontend of component based apps.
You can use sass, big picture architecture of the styles across app, and also benefit from a shared language with the rest of the team and write less css for mundane things that composition solves very easily (eg. a heading with less margin than default, a messagebox with different font and whatnot, dont create hundreds of classes or modifiers when a few utilities can do this).
Sadly most devs dont understand css precedence enough to figure out how to easily combine custom css and tailwind approach. (use bem style convention, keep specificity as low as possible, ideally 1 )
Does Angular natively solve at least part of the problems that Tailwind / CSS-in-JS with the way it scopes it's CSS?
With Angular, it's generally quite simple to figure out where the CSS for a component lives (it's literally right there in its own file alongside the component).
Sharing common values (e.g. colors, borders, paddings, etc) across classes was the biggest issue we faced, so I can see Tailwind being useful there.
In our project, we've somewhat solved it through a mix of sensible base styles and classes ('btn'), custom classes (e.g. `clr-primary--500`), CSS variables (e.g. `--clr-primary-500`) and SASS mixins / functions. It also makes it really to switch out themes dynamically, switching b/w dark and light modes for example, just requires switching up the CSS variables.
I agree with most of the points in the article except the mention of using CSS in components. IMO CSS in components only really works in some situations when the component is very small and there isn't much CSS.
I love Svelte, it's my main framework these days, but after many years in React/Vue/etc of trying in-component styles, I've gone back to good old SCSS files.
It's a bit tedious to manage Component.svelte and Component.scss but there's such an elegance to writing pure SCSS. Not only your component files become much simpler, just markup and logic, but you can use SCSS as it was intended. With vars, mixins, third party utilities like Bourbon, etc. The separation of concerns feels awesome. Like going back to the ZenGarden of yore.
As someone who's been familiar with tailwindcss for a while, it's undeniably huge benefits first hand AND also having worked with other popular CSS frameworks on production codebases this thread is a reminder yet again of cautious you have to be of comments on any public forumn. So much confidence and denial based on trivial details that would've been cleared up with barely a week of usage. Why comment at all (especially with so much confidence) when you clearly don't have experience of something? How many other topics have I been influenced on that I don't know much about, by unfounded confident opinions based on absolutely nothing?
For me (and many others) it's been a game-changer, but I didn't truly appreciate it until I actually tried it.
There's a lot of help available, and I highly recommend Adam Wathan's Youtube channel (https://www.youtube.com/channel/UCy1H38XrN7hi7wHSClfXPqQ/vid...) where he has several livestreams of actually building pages using Tailwind. Watching a couple of these went a long way to convincing me that Tailwind was worth trying.
I have been using Tailwind CSS for about a year now, both on my own product and 2 products from 2 different founders I work with from On Deck.
Here is what I have to share:
1. Tailwind Makes Your Code Difficult to Read
Tailwind CSS, in my opinion, is the easiest to read and understand what is actually happening. Yes I agree there is a learning curve to the shorthand notations but the naming is not bad at all as the author says. A couple days of light use and the system was in my head. Saying this as a full-stack engineer who deals with React + Python and devops. So I do not ONLY look at CSS shorthand notations all day.
The example with the really long string of Tailwind CSS classes do not occur with me since such a complex string of classes is probably going into a component that needs customization from React component parameters. So I build the Tailwind CSS class names line by line with if-blocks or similar.
2. Tailwind Is Vendor Lock-in
"Once you build an app with Tailwind, moving it to any other CSS framework or library in the future is going to be grueling." - the whole point of Tailwind CSS is not to move to a framework. Your JS components mixed with the CSS are exactly your own branded framework. I am not sure I understand the move argument.
Even though all the products I work with are small, we have new frontend engineers helping out and it took them less that an hour to find the right Tailwind CSS class and making pixel-perfect components. This is close to CSS yet comfortable to see and existing project and contribute.
3. Tailwind Is Bloated
Purged Tailwind CSS based stylesheets are ridiculously small. Try it out for yourself. (1)
4. Tailwind Is an Unnecessary Abstraction
Again, like I mentioned, I was even nervous that new people will not like the abstraction that Tailwind CSS has. But once you see an existing, well setup project, its so easy to check documentation and contribute. The abstraction is super thin on top of CSS.
"If it’s not already obvious, @apply completely violates Tailwind’s founding and guiding principles." - no it does not. Tailwind CSS exists to create your own style framework. It is that simple. Once you see patterns, you use @apply to codify them and reuse. That is so convenient. It is a feature in my opinion and a really important one as your project grows.
I want to stop here, but I feel that these 4 points are not strong counter points to someone using Tailwind CSS for a year over a few projects now.
Tailwind seems best-suited for the HTML panel on a CMS being controlled by a team that only knows the most basic of HTML and CSS, rather than by the dedicated development team. Having a front-end developer code the CSS for the project seems like a better idea than to scatter the design around the site’s HTML. The shortcut of Tailwind on huge projects feels like part of the mindset that now gives us websites with huge download sizes that frustrate mobile users because the team didn’t get the time to code efficiently.
tailwind ramp up is kind of jarring at first, but any verbosity is 100% made up in the prototyping and maintenance phase. i can't tell how much easier it is to just dev my components structure + style and have it reflected instantly vs trying to think of some clever div class then go to the stylesheet and work there. months later when you are re-visiting your widget you have to get back up to speed on exactly how things are structured. with tailwind i can instantly see it and adjust.
This is exactly what every "why I don't like tailwind" piece misses, because most of the people writing them haven't actually used it for more than a week (if that).
Personally I'm not a fan of tailwind BUT I always end-up creating my own utility classes (eg. .font-bold, .flex, .flex-center) and use them in combination with normal classes, just like modifiers.
So I do something like <div class="button text-center">.
I am not sure if I could actually include Tailwind and just use their utility classes for my needs, in combination with the normal CSS usage, or that would make things confusing.
Look, I don't like Tailwind as much as author but I think author make several weak points about tailwind weakness (apart from the hard to read part). Here is the better argument about why you should not use tailwind:
Nice article, just some of my opinion on the points raised:
> In my personal experience, poor naming conventions (or just poor variable names in general) are the source of a lot of confusion when other people read your code. I would rather look at some CSS that has padding: 0.25rem or margin: 0.5rem instead of trying to mentally map Tailwind’s p-1 or m-2 to their CSS equivalents.
Short names for commonly used concepts helps readability (quick to read, takes up less space) and makes it less tiring to type + change. It super tiresome to write long winded CSS (media queries are especially bad for this) and then find out you went in the wrong direction and have to rewrite it.
> Look, I don’t like Tailwind for lots of reasons. But none of them are nearly as concerning to me as vendor lock-in. It’s why I don’t want to invest time in migrating existing projects to Tailwind, and why I’d be reluctant to use it for any new projects.
Is this a real concern? I've migrated sites from custom CSS -> Bootstrap, Bootstrap -> Foundation, Bootstrap -> custom CSS etc. and it's always painful not matter what. At least with utility classes, you don't get problems where you're scared to delete CSS because you're never really sure where it's being shared. You generally just want to rip out all the previous stuff too as combining two frameworks isn't practical.
> For starters, if you’re not sure what to call that <div> in your markup, consider whether it’s actually needed. One of the great things about the Semantic CSS paradigm is that it forces you to structure your markup logically and meaningfully.
I think what makes utility classes nice for custom designs is there really aren't good semantic names for a lot of things that are only there for presentation reasons. Like I need to put a <div> around the heading + intro text so I can add some padding between those and the screenshot under it...so call it `.intro-wrapper`? Now there's a CSS quirk that requires me to wrap that all in the <div> so call it `.intro-container`? I want to make the three lines of the header animate in one by one so call them `.header-line1`, `.header-line2`, `.header-line3`?
It's tiresome coming up with name for stuff like this you only use once and even more so when you're experimenting and might not even need them. It's just noise that requires you to keep jumping between your CSS and HTML definitions to get anything done. Use semantic HTML tags like <header> <h1> etc. and custom class names for things you're sure you're going to reuse though.
Either way, utility classes is yet another "it depends" choice where there's no single answer. Use it where it makes sense.
Having just built a project with Fela, I'm curious if anyone experienced with it have a take on how it compares. I immediately rejected Tailwinds because I do actually prefer to write CSS. The end result in the HTML is about the same (garbage pile of classes, biggest difference is they're meaningless).
My issue with tailwind is the absolutely arbitrary naming scheme, I developed something similar to tailwind but the CSS naming was created to be mnemonic and use common property values (based on top 10,000 site CSS property values and few extra). `display: flex` was `di-fl`, `display: flow` was `di-fw`, etc.
Many good arguments against tailwind here. The whole approach of using a framework with opaque variable names and not chaining instead of real CSS can be criticized, and the article does it well. Though maybe I missed it, but it is actually nice to write a site with such CSS frameworks, be it tailwind or something else, so that should be noted. Reading the code and changing it, that's a different story.
However: The author writes a good critique here, and then destroys all of it by favoring the eternal sin of CSS-in-JS instead. If tailwind has its flaws, CSS in JS is the worst approach thinkable, something no web developer would ever do. I'm aware that it's used in the JS framework niche, but that's not web development, that's app UI development in a browser and seems to come mostly from web-foreign developers. If it's that or HTML with tailwind, then tailwind is always better.
CSS-in-JS originates from the needs for reusable and/or separated web components, so if your website can be factored like them it might be better. To be sure, I do hate "do it in JS" movements and I will gladly get rid of them if I can achieve the same without JS, but it is way better than keeping your HTML (templates included) and CSS (Sass included) in sync. Tailwind does nothing in comparison; it is just an abbreviated inline CSS with opinionated defaults.
I quite agree, especially with the second paragraph.
What I see as main "advantage" is that it stops developers from trying to be smart. With Tailwind first idea when creating a new component is using some combination of existing utility classes and it will be probably more or less ok and consistent with rest. Without Tailwind, developer will probably start create new classes, possibly duplicating or reinventing lot of existing stuff.
A bit tangential, but I started using Chakra UI on one of my projects and I really like it. Performs much better than Tailwind probably because it comes with batteries included and I almost never have to touch CSS in any form.
I seem to have noticed something about these Tailwind love/hate discussions. And it all boils down to this:
Old-school devs seem to like TW for the benefits it gives over other CSS paradigms (Smacss, BEM etc.) It speeds up development over those. Testing and editing in the inspector is simple and easy to put back into the source.
New-style devs (SPA ALL TEH THINGS!!) do NOT like TW. They are already dealing with 3 concerns in the same file. Adding another layer of abstraction is unwelcome. Changes seem to multiply and search/replace makes seemingly simple adjustments a royal pain.
Then there are the Bootstrap acolytes who won't give up their btn-default no matter what comes along.
All I can say is to each their own. But Bootstrap guys(and girls)...it's time to move on. :P
I skipped to the "what should you do instead" and the code examples the guy gives are laughable. Would rather have that in your code or a few utility classes in your components?
I'm happy to see the discourse has shifted from "WTF, who would ever think Tailwind is a good idea?" to at least trying to give some arguments against using it :)
If pure CSS is like cement - form it however you like, but you need to do it over and over again, and Bootstrap is like those colored wooden building blocks children used to play with - you get your standard shapes and that's it, but most easy to use, than Tailwind is like Lego - you can't form freely like with cement but have enough freedom to build creative designs based on *given* standard building blocks.
That's how Tailwind won me over.
Sooner or later most design-devs (devs doing design as well) end up using some kind of utility classes. Using Tailwind from the start saves some serious amount of effort and provides a standard across projects and teams.
My biggest problem is components, I just need more than a utility class framework for my side project, I do not have the time to implement all the components myself.
I often use bootstrap-vue (and used vuetify on a recent project). The accessibility, documentation, testing, and consistency these projects bring to my vue projects is big. BV uses bootstrap. I can make modifications as/when needed, but I have a whole library of these components that are documented and are styled using bootstrap.
Having to rebuild these sorts of things just so I can use tailwind is... hard to justify. I was able to semi-combine both in a recent project, but it seems a little fragile.
Is everyone else just building all their components by hand all the time?
I’m in this boat and would also love to hear what people are doing. I checked out the Tailwind companion component library, Headless UI (https://headlessui.dev/) but it seems like very early days indeed.
true, there is a learning curve. But this is over relatively quickly once you learn that "w" stands for "width" and "h" is for "height", and the screen size prefixes map as you would expect from default to medium to large.
as for scanning left to right... the enter key is right there. my VSCode autoformats the classes to break lines just fine. its probably the tailwind plugin doing that.
2. Tailwind Is Vendor Lock-in
first of all, "vendor lock-in is bad" is a poor kneejerk reaction. we all buy in to vendors at some point. eg with frontend frameworks. and as far as vendor lockin goes, Tailwind is extremely light - if you want to stop using it, freeze the generated output, and then continue writing css in whatever new way you choose. this is far LESS vendor lockin than alternatives like styled components and css modules, which force you to make specific js and build tool choices. and all of these are open source so this again is an order of magnitude less lockin than anything proprietary, which is where this argument really starts being at all useful.
3. Tailwind Is Bloated
how is declaring things on the docs indicative that "its creators have tried their very best to hide this fact from you."? they've just decided on sensible defaults. the bloat only impacts development and builds. This contrasts to the problem that utility css solves, which is bloat inside of hard-to-maintain append-only CSS with lots of duplicates, which actually affects users.
4. Tailwind Is an Unnecessary Abstraction
components. use components to repeat stuff. this rant on @apply takes things way overreacts, calm down.
5. Semantics Is Important. Tailwind Forgoes It.
counterpoint: naming things is hard. Tailwind names css utilities for you so that you don't have to come up with custom names for every component.
6. Tailwind and Dev Tools Don’t Play Nicely
au contraire, tailwind plays VERY well with devtools. https://twitter.com/swyx/status/1265745431448838144?lang=bg (since this video I even learned that you can type in the classname box in chrome devtools and it autocompletes nicely for you
> my VSCode autoformats the classes to break lines just fine.
My only pain point with Tailwind was the order of classes. It helps with readability if the classes are always in the same order. I just discovered that eslint-plugin-tailwind [0] is solving this exactly. Configuring VSCode to run code formatter and perform ESLint fixes [1] is just an incredible DX.
For me Tailwind CSS solves a cognitive problem: I find that switching between CSS and HTML files reduces my development velocity substantially (maybe I'm getting old).
I was always a bit wary of CSS frameworks, and I preferred writing "actual" CSS and used mostly CSS/SCSS before I discovered Tailwind CSS. Interestingly, even before I discovered Tailwind CSS, I was already getting into the habit of using utility classes like "flex", "flex-wrap", because it made a lot more sense *to me* to see those in the HTML.
I personally find the examples given in the blog post contrived. Take the "hard to read part", for example, this is how I normally format my HTML using Tailwind CSS:
Even if you are using styled-jsx or any framework that gives you the ability to write "regular" CSS, it still wouldn't beat the example above in terms of readability. As such, the following paragraph just doesn't make sense:
> I’m comfortable reading other people’s code, and making sense of their logic and relating their markup to their CSS.
Assuming that we are not talking about component-scoped styling here (otherwise the point made would be moot), with Tailwind CSS you can instantly relate CSS to markup without switching between files and hunting down all relevant class names in the example given above; this is arguably also easier when you are not working with the source and just debugging on the front end.
> But if I have to look at ~1000 LOC changes in a PR, and most of that is coming from long strings of class names, I’m not going to be happy. It’s also going to be more difficult for me to make suggestions that could eliminate redundant CSS or simplify your markup.
I have never dealt with ~1000 line of changes in a single PR, but that sounds pretty broken and there is an abstraction problem that is much worse happening elsewhere and irrelevant to the argument.
The last line also sounds like a throwaway without any solid example to prove it: even if switching between markup and CSS files is not taken into account, I can't imagine hunting down redundant CSS would take longer with Tailwind CSS. If the redundant classes are on the same element you can see it instantly; if they are on different elements, it would still take similar amount of work to debug and find them? Assuming that there are no redundant classes, then there isn't much to be simplified because the whole point of Tailwind is to have (managed) complexity in the markup instead of having it in the CSS. I personally would rather have it in the markup, but that's just me and I can't say if it's better or worse.
> With Tailwind, you’re forced to interpret semantics on the fly.
I find it easy to just ignore class names and focus on content when I need to with the way I structure my code. Maybe a lot of people don't realise that it's okay to, or feel comfortable with, splitting class names and attributes onto multiple lines.
Just one more point on being bloated, note that on Tailwind CSS's website they say:
> Tailwind automatically removes all unused CSS when building for production, which means your final CSS bundle is the smallest it could possibly be. In fact, most Tailwind projects ship less than 10KB of CSS to the client.
For reference, the blog's CSS is 12.12 KB gzipped.
Most of the rest of the post follows a similar pattern that's just out to trash Tailwind CSS. As others have already pointed out, this may end up being a 50/50 thread of personal opinions after all, but it seems that we keep getting more and more of these sensationalised hate posts that are just based on personal preferences...
No one will see this comment buried under 200 others, but if you made it this far checkout basscss. It's the only css framework that ever has made sense to me. Devs keep recommending Tailwind to me and I honestly don't understand what they see in it, I feel like I'm taking crazy pills.
At the end of the day, sure if you don't like it - don't use it. But I don't understand the hate for it, because I have a very different experience with it.
---
> 1. Tailwind Makes Your Code Difficult to Read
This one is interesting to me. I think devs should take responsibility for writing easy to read code. A framework is a framework. I agree shotgunning classes all over markup is messy, but Tailwind doesn't do that - you do.
I would encourage the author to understand the concepts of extracting[0] and defining components[1] within Tailwind. That can make things very easy to read by the author's logic.
> 2. Tailwind Is Vendor Lock-in
Not necessarily. Especially if components are defined, if anything it makes it easier to change. Because you have a css class abstracted at the same level of your markup. In the world of various competing component frameworks, I would argue the opposite is true. You can just as easily apply tailwind component classes to Vue as to React as to Svelte etc.
> 3. Tailwind Is Bloated
As others have mentioned purge css[2]
> 4. Tailwind Is an Unnecessary Abstraction
"Because instead of repeating styles in your CSS, you’re now repeating them in your HTML", "you’re still writing the exact same amount of CSS, disguised as class names" This just isn't true if you use it correctly again see extracting and defining components.
> 5. Semantics Is Important. Tailwind Forgoes It.
Author recommends BEM and then in the end says "You don’t really need BEM, either". I agree with component scoped css, BEM is less important. Tailwind
> 6. Tailwind and Dev Tools Don’t Play Nicely
What? Anyone who experiences this should revisit CSS order of precedence. It behaves exactly as expected. I've never had a problem with chrome/firefox dev tools.
> 7. Tailwind Is Still Missing Some Key Features
So use css? Using tailwind isn't a binary option. You can use both tailwind and css. It's a tool, use it where it makes sense.
> So use css? Using tailwind isn't a binary option
then what, you now have 2 set of styles in 2 different places, written in 2 completely different ways, does that sound fun to maintain? I guess still you have to structure your css in some way too?
Why is it that Tailwind causes such emotional reactions in people? Functional CSS has been around a long time now.
When functional css ideas were introduced it presented a novel solution for scoping issues, naming issues and bloat issues. I remember discovering basscss and tachyons around 2015. The paradigm immediately felt like a huge improvement in my workflow. The iteration was so much faster than what I was used to with Bootstrap, BEM, or SCSS- I felt like I could design in code for the first time. My favorite workflow for web design became loading basscss in a CodePen, with almost no idea of the outcome I wanted and iterating towards something. What’s kind of amazing is that it allowed for these sorts of quick sketches and improved maintainability in large projects.
It also led me to my first inkling of a design system- through the use of composable and constrained styling primitives. A lot of the ideas introduced with those libraries now saturate the frontend ecosystem. And keep in mind, functional CSS, or at least the principles behind it have evolved a lot since 2015, particularly when it comes to components and CSS-in-JS. The original creator of basscss has gone on to create a number of equally impressive projects that advance the main ideas: styled-system, rebass, basically everything from @jxnblk.
I haven’t used Tailwind or any other functional CSS philosophy over the past few years since I find primitive and composable styling components, CSS-in-JS, themes, and CSS variables offer even better workflows for building the applications I work on. When Tailwind initially made a splash I was already pretty into what I consider this next phase of styling libraries- so I was a bit confused why people were so excited about it when basscss and tachyons had been around for years. Looking through the docs it seemed like they had taken basscss and tachyons and layered a bit of Bootstrap on top (in the form of nicer visual defaults and some component patterns).
Outside of the core functional principles, I don’t like the idea of Tailwind as much as I do basscss/tachyons. I think Tailwind tries to put too much of your styling in atomic classes. Part of what makes basscss great is the small API and the constraints it introduces on reusable patterns. I don’t want all of CSS to be represented as atomic classes- just the stuff I reuse 90% of the time. It also seems like a bit too much tooling when one of the main advantages I saw in the older libraries were that they were just plain CSS- you could use them on pretty much any project, regardless of build tools or architecture. I used to start with basscss on a project and then add my own layers of patterns on top- extending the system as needed.
That said it still offers a lot of the good stuff, combined with great documentation and more thought put into component patterns. It’s a great starting point, especially if you don’t want to or can’t take on runtime costs for CSS-in-JS (this is also evolving but still a concern). Its success isn’t a fluke or a result of misdirection as the author of this critique alleges. Reading through Adam Wathan’s original post on functional css (https://adamwathan.me/css-utility-classes-and-separation-of-... he describes the exact same trajectory in CSS thinking I went through as a frontend developer through the 2010s. It’s a great read and I think speaks to the level of consideration put into the library. If I were to try a new project today using functional CSS I’d definitely give Tailwind a shot.
I just started using Tailwind for a small project and love it! I thought I'd respond to the author's points:
> Tailwind Makes Your Code Difficult to Read
I think this is a preference, not a fact. I tend to write 2-dimensional CSS (I know the standard convention is 1D) so seeing a bunch of classes one after the other on the same line doesn't bother me.
Regarding the abbreviations being difficult to parse, I don't find it so. And, do you want short class definitions or do you want long and descriptive class names?
> Tailwind Is Vendor Lock-in
I'm not convinced. Every framework is lock-in. Otherwise there'd be no point.
> Tailwind Is Bloated
Possibly, but it seems to trim itself down when compiled to production quite nicely. Paired with minification/gzip, doesn't seem like such a big deal.
> Tailwind Is an Unnecessary Abstraction
I like the promises it gives. "Here are some predetermined boxes your design can fit into, if you need to change them, do it via the config." In other words, you're constraining yourself. I think this is important. Even on teams with designers, the design can evolve over time and you'll have one section of an app looking different from another. Tailwind enforces a set of good practices. Maybe I like this because I'm not a great designer at all, but it seems to me this kind of constraint could have helped many projects I've worked on in the past (ones that had professional designers).
Secondly, regarding "What exactly is the difference between using @apply and just using the CSS rules that correspond to your utility classes?" Well, because your utility classes are still subject to the constrains I mention above. The documentation specifically only recommends doing this for places where something is too small to be its own component, but too common to repeat the same class names over and over. Sure, you can misuse it, but I found the documentation obvious how the best practices here.
"Because instead of repeating styles in your CSS, you’re now repeating them in your HTML, through class names." I think Tailwind specifically makes sense in the context of components. If you're repeating the same classes over and over again, you're doing something wrong.
> Semantics Is Important. Tailwind Forgoes It.
I can see both sides to this. The one comment I'll make is that in the cases where I've vehemently stuck to semantics, it has been wonderful to build but horrible to change. Semantics makes a tone of sense, until things start shifting around, and then you've got half of your classes referencing some object that's no longer there, or a thing that used to live here, but now lives there, and only some of the styles moved and some were copied etc etc.
When I first saw Tailwind, I thought "wow, this is just inline styles++, how stupid." Now I kind of see the magic behind it.
> Tailwind and Dev Tools Don’t Play Nicely
This might be true, I haven't really done much devtools CSS debugging with TW yet.
> Tailwind Is Still Missing Some Key Features
It also defines "dark" but I haven't seen anything about custom themes in general. What if I have more than just a normal mode and dark mode? I'm curious how one would build themes on top of TW.
> With frameworks like React and, more recently, Svelte, it’s never been easier to write CSS without leaving your markup, and without resorting to inline styles. You don’t really need BEM, either.
This is true, and I'm excited to try and build something more complex in Svelte and see how it goes.
I'm too old and tired to try to be clever on the front end any more. TailwindCSS is the right answer for big projects and for small. Yes it can get bloated but i'm willing to take that trade off if it means I don't have to do any more css.
Huh, my opinion is that it’s potentially the right fit more middle-sized projects, but neither big nor small ones.
For small projects, you’re wasting time with a massive abstraction layer when you could be writing a small set of easy styles in plain CSS. You don’t need the weight and complexity of a sizeable framework.
And for big projects, it’s technical lock-in and additional maintenance overhead that absolutely doesn’t work if you’re trying to coordinate a microfrontend environment for example.
For small projects you don't have to create any boilerplate styles, resets, and the like...you just start writing code. A lot of frontend frameworks that are popular these days have CLI options to set up Tailwind out of the box at the same time you bootstrap the rest of the files.
For large projects, maintenance is easier because you don't have to relearn the CSS architecture each time you (or more importantly, someone else) comes back to work on something after a few months. If you're doing microfrontends, just import the same config file?
I'm not a huge Tailwind fan either, but this author is missing something major in his obsession about long lists of utility classes. The @apply directive is there to convert utilities into semantic classes, and eventually that's where you get on a Tailwind project.
Where Tailwind is different is the development process. One problem with CSS is that before you can do anything, you have to come up with a class, ie some abstraction. You then start using that class all over your code until over time you realize it is the wrong abstraction.
What Tailwind lets you do is get going without having to create any abstractions. Then as time goes on you see the repeated patterns in your code and can use @apply to refactor those into the correct abstractions.
So you end up in the same place as traditional CSS, but the trip is much smoother.
The author's complaints about pseduoclasses and break point are spot on though, and he only lightly touches on pseudo elements which are another huge black eye for Tailwind.
It's really sad to see novice developers rediscover and revisit arguments from decades ago, but that's really the curse of software development, isn't it? Why does Tailwind CSS even have some kind of brand name? It's just bad CSS. It doesn't need a name.
The CSS specification says nothing about how to map styles to classes. So when you say "bad CSS", maybe you mean bad methodology? Bad for what? Bad for whom?
You probably weren't alive yet, but the CSS methodologies that originated from the CSS Zen Garden made sense in an era when XML was supposed to take over the world. But it didn't, and there's no sense hanging on to those promises.
ps. Media queries were not a thing twenty years ago.
The reason XML didn't take over the world, and we're left with this mess of garbage for a front end, is because of bad developers like you. Mistakes in the past are no reason to continue making mistakes in the future. From your example, the obvious solution would be to write better markup instead of writing worse styles.
I switched to TailwindCSS a long time ago and I have zero regrets. Its so awesome I can switch to a project that is 2 years old, and make a quick layout UI change without having to look at old CSS files to find classes etc. I also can just find a tailwind class name and apply lots of cool stuff that I've normally found difficult to do via "pure" CSS files.
But I also feel that this is likely to be a thing that half prefer A, and half prefer B, and there is nothing wrong with either. In this thread is likely to be a 50/50 split between both camps, with different "ideologies" on how the front end should be done.
As the author of this article says - give it a go. If you like it, awesome. If you dont, switch back to another tool, there's not a definitive "right/wrong" answer to any of this.