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.
>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 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.
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.
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.
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.
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.
> 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).
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.
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.
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.
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.
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.
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).
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.
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 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.
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
> ... 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.
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.
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.
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).
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.
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.
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 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.
"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.
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.
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.
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.
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.
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.
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.
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.
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.
> 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.
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.
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
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.
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
> 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.
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".
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?
317 comments
[ 4.3 ms ] story [ 408 ms ] threadThe 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.
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.
Your problem here is thinking of JSX as HTML instead of what it really is – a thin syntactical layer on top of Javascript.
what kind of argument is that?
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.
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.
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.
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.
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.
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.
Just RTFM.
OP wrote:
> 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.
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)
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).
If anything, Tailwind is the opposite of bloat.
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.
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.
But I think this could be solved with an editor extension that shortens or hides the 'class' unless you mouseover it
Don’t knock until you’ve given it a fair chance.
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.
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.
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).
Isn't the flip side of this that it makes it almost impossible to keep styles (visually) consistent across the codebase?
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.
Tailwind: https://tailwindcss.com/docs/theme#spacing
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 sometimes wonder if people even understand what technology they are using:
CSS = Cascading Style Sheets
Go read some history, as to why exactly they were created. What you are describing is not CSS at all, that's properties on a design grid.
Which goes back to the author's point - if you want or really need that, don't use CSS. Just use components with standalone properties.
Use CSS when you want to be 100% sure it will change everything else.
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.
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.
There's only two ways to avoid it: having very small, very cohesive, teams, or using tools and methodologies that avoid this.
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
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.
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.
And then combine it with Sass
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.
Others view compartmentalisation as important to ease of reading, letting them focus on one level at a time.
I wonder how well the preferences for tailwind align with people's views on unit tests in the same source file?
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.
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.
Or define components? https://tailwindcss.com/docs/plugins#adding-components
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?
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.
To each their own: for instance, I used Sass but disliked it. It always seemed to add needless complexity to my projects.
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.
[1] - https://planflow.dev/blog/the-main-advantage-of-tailwindcss.
When I'm creating an element having it styled as-I-think, without having to switch to another file is a nice productivity boost
Especially if you have some sort of real-time rendering on your local server
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).
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.
> 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.
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.
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.
(1) https://tailwindcss.com/docs/optimizing-for-production
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.
Original HTML could do it in table cells. What's taking CSS so long.
Anyway it's easy and has been for ages:
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.
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.
We are owed a better API, let’s get the right people on this.
div { display: grid; place-items: center; }
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).
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 :)
If I’m going to use custom properties it would be in a way that plays to CSS’s strengths.
.card { color: c(gray-700); }
Same for font sizes, font family definitions, screen sizes.
I like having to remember less stuff, within my scss definitions.
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.
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
[0]: https://package.elm-lang.org/packages/rtfeldman/elm-css/late...
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.
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.
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.
[0]: http://web.archive.org/web/20191222080351/https://diablo4.bl... & https://twitter.com/tailwindcss/status/1190423327590027264?s...
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.
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.
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're still using CSS...just more efficiently.
Tailwind is much closer to raw css than some of the SASS, LESS, and Compass mix-ins I have had to wrangle.
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.
```
```can be a function that expands to:
```
```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.
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 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.
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.
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?
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.
in a rare case where CSS actually seems to have an intent rather than throwing spaghetti at a wall to see what sticks
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.
How on earth can someone end up so cognitively dissociated?
---
> 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.
---
[0]: https://tailwindcss.com/docs/extracting-components
[1]: https://tailwindcss.com/docs/plugins#adding-components
[2]: https://tailwindcss.com/docs/optimizing-for-production
[3]: https://jigsaw.w3.org/css-validator/validator?uri=https%3A%2...
> 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?
<div class=" w-16 h-16 md:w-32 md:h-32 lg:w-48 lg:h-48 "></div>
do you just casually throw these magic numbers everywhere or there is a way to use css variables with tailwind?