DEV Community

Kerry Boyko
Kerry Boyko

Posted on • Updated on

TailwindCSS: Adds complexity, does nothing.

If you work in the front-end, you've probably heard a lot about TailwindCSS, a CSS library, much like Bootstrap. Much unlike Bootstrap, however, Tailwind takes a different approach - it is all "utility classes".

And I am not a fan. I got a whiff of it and quickly learned the name is appropos: it was as welcome and useful as passed gas.

Before we start, let me try to explain what a utility class is. Let's say that you have many components, and many of them need to have the CSS style property: "display: flex;". Instead of writing that over and over in your css, multiple times, instead you create a class called "flex"

.flex {
  display: flex;
}
Enter fullscreen mode Exit fullscreen mode

Then, in every component that needs to be flexed, you add that "flex" class.

This is not a bad thing. I have written, and used utility classes a great deal myself, especially when I'm writing CSS without the aid of CSS-in-JS solutions or a preprocessor like Sass/SCSS.

What Tailwind does is take that concept to the extreme, with the idea being that you almost never have to write CSS, you just write different classes based on what styles you need to apply.

Which is an interesting choice, because...

This is just inline styles with extra steps

This is just inline styles with extra steps.

That's it. Writing <div class="flex">foo</div> has the same exact effect as writing <div style="display: flex;">foo</div>. Well -- slightly different in that inline styles have higher priority than classes, but that's not really relevant in this context.

So - with that in mind, with the exception of CSS prioritization, any argument you could make against using inline styles in your codebase is also an argument against using Tailwind. For example: Lifewire: Avoiding Inline Styles for CSS Design. Or StackOverflow: What's so bad about inline CSS?. Or LogRocket: Why you shouldn’t use inline styling in production React apps.

I know it seems a bit lazy to rehash other users criticisms of inline styles to explain what's wrong with Tailwind, but it really is a 1-to-1 mapping. It's just inline styles with extra steps.

Some of the problems Tailwind shares with inline styles:

It's WET, not DRY.

When you want to change your site styling in a major way, if you've used utility classes, you need to go through each use of those utility classes - that is, every component - and visually determine what needs to be updated. For example, let's say that your company's primary color is blue. You'll have lots of blue stuff in your website, marked with things like: "text-blue-500" or "bg-blue-300" to determine different shades of blue. And that's fine until your company decides to rebrand, and all of the buttons - but only the buttons - on the site need to be red.

Now you have to go through each component and manually change "text-blue-500" to "text-red-500". And with 1000 edits comes 1000 oppertunities to introduce a bug. It is almost a textbook definition of why the DRY principle is in place.

Alternatively, if you're using regular-old CSS, what you probably did is create a class called ".button". You can just go into that class and change a single line: "background-color: 'red';". Any element that uses that class definition will now be red.

That brings us to the next point:

HTML should only concern itself with the structure of your page, not the styling of the page.

People talk about seperation of concerns a lot in development. CSS Modules (and especially .vue files) have done a lot to dispel the notion that you need to segregate structure, behavior, and style of the same basic building block of your site in seperate folders, but there is something to be said for seperating concerns. That is - each part of your code should be "loosely coupled and highly cohesive."

In other words, your HTML (structure syntax) shouldn't have information about what the styles should be, it should only contain information about the structure of the page.

Indeed, the ultimate reason for the invention of CSS, the whole point of the entire enterprise of CSS... was specifically so that you could seperate content from presentation.

And the method for doing this is through the "class" attribute.

The whole point of "class" is specifically that you can tell the computer what an element is - that is, describe an element's content. Once you've defined the content, then you just need to decide what content of that type should look like.

This not only means that you can go and change how an element looks without worrying about the underlying structure of the page, but also means that you can use these classes to describe what an element is. Indeed, part of the reason for BEM's naming syntax is that BEM names not only tell you what the component is, but also what it's relationship to other components in the document is.

Remember that when we write code, we write it for two audiences: the first is the computer itself, which doesn't care how the code looks so long as it runs, and the other is your fellow programmers. The easier it is for them to quickly identify what parts of your program are and how they interrelate, the more quickly that they can fix bugs, add features, and bring value to the organization.

Which brings us to:

It's hard to read

If you look at some HTML with Tailwind in it, you might say to yourself that the HTML looks "busy" or even "ugly." That's true, but it's missing the point.

Say what you will about inline styles, but they're at least providing enough context to let you know what's happening. Tailwind code is full of semantically obscure abbreviations; most of which are just redefinitions of already well known CSS properties.

Worse still, when they're not redefinitions, they can become downright cryptic. Tailwind prefers to use prefixed class names instead of media queries. Here's an example from Aleksandr Hovhannisyan

So this in Tailwind:

<div
  class="w-16 h-16 rounded text-white bg-black py-1 px-2 m-1 text-sm md:w-32 md:h-32 md:rounded-md md:text-base lg:w-48 lg:h-48 lg:rounded-lg lg:text-lg"
>
  Yikes.
</div>

Enter fullscreen mode Exit fullscreen mode

could be expressed as:

<style>
.thing {
  width: 16px;
  height: 16px;
  color: white;
  background-color: black;
  padding: 0.25rem 0.5rem;
  margin: 0.25rem;
  border-radius: 0.25rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
}

@media screen and (min-width: 768px) {
  .thing {
    width: 32px;
    height: 32px;
    border-radius: 0.375rem;
    font-size: 1rem;
    line-height: 1.5rem;
  }
}

@media screen and (min-width: 1024px) {
  .thing {
    width: 48px;
    height: 48px;
    border-radius: 0.5rem;
    font-size: 1.125rem;
    line-height: 1.75rem;
  }
}

</style>
<div class="thing">Yikes.</div>
Enter fullscreen mode Exit fullscreen mode

Now, the first example, I grant, is an awful lot less code to write, but look at how the second example is explictly defining height and width at specific breakpoints.

It is verbose - as raw CSS usually happens to be, but there are other solutions - such as Sass/SCSS, or solutions such as Emotion, Styled Components, etc. which allow you to use much more terse syntax without losing the cohesive meaning behind it.

Again, this is programmer 101. It's why senior developers get on junior developers for naming variables "const h = 10" instead of "const height = 10"

Another reason why the latter is easier to read than the former - Tailwind's classes are arranged horizontally, while the CSS is written vertically. The wider text is, the harder it is for a reader's eyes to jump to the next line, and the harder it is to find the one particular word you're looking for in a wall of horizontal text.

I bet your eyes started glazing over the second you saw the horizontal scroll bar on that Tailwind code sample, didn't they?

You lose a lot of the features built into standard CSS

I won't harp on this too much, but it should be pointed out that because Tailwind doesn't allow you to use the power of many of CSS's basic features. You can't chain selectors together, like so:

.foo:focus,
.foo:active,
.foo:hover {
  /* css code */
}
Enter fullscreen mode Exit fullscreen mode

You can't use combinators.

.foo p {
  /* all p that are decendants of a .foo */
}
.foo > p {
  /* all p that are direct children of a .foo */
}
.foo + p {
  /* all p that are directly -after- a .foo */
}
.foo ~ p {
  /* all p that are siblings of a .foo */
}
Enter fullscreen mode Exit fullscreen mode

It solves a problem that doesn't exist.

One of the craziest things is that there's an obvious limitation to Tailwind's utility-class paradigm. What happens if you want to group related styles together? Rarely is "display:flex;" used without "justify-content: {value}", for example. CSS allows you to group these styles together into (wait for it), classes.

There's a tool for grouping related Tailwind classes together too. It's called @apply. It's special, non-standard syntax that goes in your CSS file (a directive) and allows you to string together a collection of tailwind classes and place them all under one class name.

That is to say, completely defeating the purpose behind the utility-class paradigm. If you end up having to use @apply, then *why don't you just use normal, ordinary, conventional CSS, which is easier to read, understand, modify, and doesn't require special tooling or parsing. CSS syntax can be complex, but it's been pretty stable since the late 90s, and isn't going to radically change anytime soon.

There's a very simple mental experiment I'd like to conduct with you.

Imagine a world in which CSS was never developed, but something akin to Tailwind was. That is, webpages could only be styled through repeating these individual class names... presumably through using table tags for layout. (To give you an idea of how old I am, I used to code web pages as a summer job in my junior year of high school in 1996 - and we used a LOT of table tags.)

If you could go from the limitations of Tailwind to CSS, wouldn't you consider that a quantum leap forward? Expressive syntax! Semantic naming! Style grouping! Selectors and combinators!. It would be like moving from Assembly to C for the first time. If so, why are we considering replacing CSS with something that does less, is more complex, creates bad quality codebases, and possibly ends up with massive vendor-lock in down the line?

If you want better than CSS, there are already solutions.

So a lot of the hype around Tailwind is that you can get rid of CSS. I know, everyone knows CSS can be hard to work with - especially if you have legacy codebases where the CSS wasn't written that well.

But for the most part, there are other, better improvements on CSS that actually do make styling simpler. There's the various CSS-in-JS solutions that allow you to leverage the power of Javascript to create dynamic class definitions; there's preprocessers such as Sass/SCSS/LESS; there's linters like Stylelint; there's best-practices methods like BEM/SMACSS. Is there overhead in learning these technologies? Yes. Is there tooling that needs to be part of your build chain? Yes. But unlike Tailwind, all of these solutions actively provide a tangible benefit to your code -- which is something that Tailwind can't claim.

It literally provides no value, and tons of problems.

At the end of the day, what do you get for all these problems? What are you left with? You're basically left with a less readable, more complex version of inline styles, a coding technique that we've been trying to breed out of junior developers for the past decade or so.

If you adopt Tailwind, it's going to provide problems for you and your team for years to come, and it's going to be hard to remove it.


Updates based on the comments section.

A few notes based on responses from the comments section.

Why trash something if you don't like it?

It's important to write about bad frameworks as much as it is to write about good ones, because of two reasons.

First, is the John Stewart Mill argument of "the value of the wrongful idea" - that in making a (good faith) argument for something incorrect, one arrives at a more correct, more complete view by analysis and refutation. Ideas must be continually challenged lest they go stale. Indeed - "one who doesn't understand one's opponent's arguments does not understand one's own" is a maxim I try to apply. When I wrote this article, I tried to look for the good in Tailwind. Why do people like it? (They don't have to write css. They can put style info in their HTML. They can write terser code. It gives them power to do things they don't know how to do in css.) Once I knew why people liked it, I had a much better understanding of why I didn't. (It combines content and presentation. It makes things harder to maintain. The syntax is obscure. You lose the power to do things that you can do in css.)

Second is that someone down the line is going to think: Hmm, should I add Tailwind to my app that has to be maintained by my team? And they're going to google "pros and cons of TailwindCSS". There will be plenty of articles explaining the pros. Here's one explaining the cons. Hopefully I've made a compelling argument not to use Tailwind so that future developers won't have to deal with it.

You're being disrespectful to the people who like Tailwind.

This isn't New Orleans Jazz.

I don't like New Orleans Jazz, so I don't have to listen to it. I don't buy New Orleans Jazz albums.

I am not in the habit of making detailed criticisms of what I feel to be the music compositional problems of New Orleans Jazz.

But I have never had a team lead, product owner, or stakeholder come up to me and say: "For the next project, I'm thinking that everyone on the team has to learn how to appreciate and play New Orleans Jazz."

Engineers and developers are often required to work with technology that they not only don't like, but which makes their work harder - often because decision makers either didn't care about the software's tradeoffs, or didn't know. Can't do much about the former, but we can do things about the latter.

When team leaders are thinking about incorporating a new technology into their tech stack, they should look for blog posts like this one to help them evaluate whether or not it's worth a try.

My thesis is not, as you seem to think, "I don't like Tailwind, and therefore YOU shouldn't like Tailwind either". That's a 12 year old's viewpoint of technology criticism.

Rather my thesis is: "If you choose Tailwind for a mission critical application, you will end up making your job harder, your application more brittle, and your team, in the long-term, will suffer."

But CSS has massive problems!

It really does. And there are better solutions than plain CSS. But Tailwind isn't one of them.

Say that in the 1990s, the only way to build a house was to bang nails in with a flat rock (CSS). And then, around the mid 2000s, a really smart guy invented "the hammer." (SCSS) It took adjusting, and you have to learn a new tool, but it did the job much better.

Around the early to mid 2010s, another guy invented the nail gun (CSS-in-JS). It did a lot of the same stuff as a hammer, but you had to know how to use it. There were tradeoffs, but generally, people who chose to work with hammers or with nail-guns usually ended up okay. Many peoplee would often use a manual hammer when the manual hammer seemed appropriate, and the nail gun when they seemed to need it. And all was good in the world of carpentry.

Then in 2017, someone came up to the carpenters and said: "Hey, see what happens when I do this!" and starts hammering in nails with the butt end of a loaded revolver (Tailwind).

And it's supporters quickly point out how more effective it is at building houses than banging in rocks.

"But it's a loaded gun. It might go off and shoot someone"
"Hasn't happened to me yet."
"Why don't you use a hammer? Or a nail gun?"
"I don't like hammers or nail guns."
"I can understand why you might not, but even if you used a rock, that would be safer in the long run."
"But using a rock is so difficult and inefficient."
"I'm not saying to use a rock. I'm saying that the hammer already solves the problems you have with the rock, but even the rock is a better tool for this than a loaded gun because it won't shoot anyone."
"But I love my gun."
"I guess it's alright if you use your gun on smaller projects on your own property, but..."
"Nope, I'm the foreman. Everyone on the site is using loaded guns from now on, because they're awesome."


Update: 9 May 2021 - Check out this blog post by Mykolas Mankevicius which attempts to rebut this article. I disagree, of course, but I think it adds to the debate, and if you're reading this deciding whether to use tailwind or not, you should hear what the "other side" of this issue has to say.

Agree but think my writing style might be too abrasive? Check out Benoît Rouleau's take on this article entitled Tailwind CSS might not be for you

Cher writes about some of the response this article has gotten and how it relates to our own unconcious bias in "Sexism, Racism, Toxic Positivity, and TailwindCSS"

Top comments (260)

Collapse
 
rsa profile image
Ranieri Althoff

Now you have to go through each component and manually change "text-blue-500" to "text-red-500". And with 1000 edits comes 1000 oppertunities to introduce a bug.

Ah, if only there existed search and replace...

Collapse
 
cjpartridgeb profile image
Chris Partridge

Or just create a custom color palette in your Tailwind config called 'brand', set your colors and be done with it. If brand colors change, update the color palette - easy.

Collapse
 
kerryboyko profile image
Kerry Boyko

Right, but branding is more than just color palettes. It's also - do we want the corners to be more round or less round on buttons. What if we want to have switch toggles instead of checkbox toggles? What if we want a specific page to look like a specific brand that isn't our main brand?

(This happened with a client of ours which sold Louis-Vitton gear -- Louis-Vitton wouldn't allow them to sell LV stuff on the client's page unless the pages that they landed on were branded with Luis-Vitton's color scheme).

Thread Thread
 
cjpartridgeb profile image
Chris Partridge

Right, and Tailwind offers plenty of flexibility to manage these things via your config if required. It's not just a static set of a utility classes that cannot be altered without digging into the source - override the default border radius settings, or create your own presets for your brand if need be.

The exact use case in your article and comment (branded button) is mentioned in their documentation somewhere (I distinctly recall reading it), and I'm sure they suggest creating your own branded button class using @apply. If your branded button border radius requirements change, update the class, if the new border radius is outside the presets, then extend the config and then update the class.

If a specific client demands you brand their pages, then add a color palette for their brand, and make sure those components switch out brand for client-brand where required? Tailwind certainly doesn't stop you from using colors outside their default palette - I've only ever used the provided colors for non-brand accenting (e.g. greens for success, reds for errors, etc) and the grays for text/borders.

In regards to moving to switch toggles from checkbox toggles, you're likely going to adjust the layout of the component somewhat, or perhaps add an additional container element ensure things are aligned correctly - I've encountered this exact type of scenario many times over the years - more often than not, it's more than just a few lines of CSS.

And if you're building a modern application, you'll likely have a checkbox component or at least a rudimentary template/partial to stay DRY - which will prevent the need to update every occurrence of that particular component across your application - again, something which I believe they touch on in their documentation.

To be frank, I wasn't a fan of Tailwind at first, and I certainly don't think it's the "be-all and end-all" solution - but after using it on a few projects I've come to love what it offers out of the box (especially the font, text sizing defaults, colors for accenting, gray set, grid, gradients, screen breakpoints, space-between, etc) with the ability to extend/override anything I desire if the case arises.

It's really allowed me (as a full stack developer building business applications) to start flowing without having to worry about any of aforementioned when I just want to get something clean, consistent and functional on the screen.

With all that being said, if you're creating basic web sites, landing pages, marketing pages - or complex applications without a component framework - Tailwind probably isn't the solution you want.

Thread Thread
 
kerryboyko profile image
Kerry Boyko

The problem is that the minute you start using @apply and using semantic classes again, you're moving outside of Tailwind's "utility classes" paradigm.

Now - while I could argue that "you might as well just write out the CSS" there is some value to alternative syntaxes. There's all sorts of tools for transpiling non-standard code into standard code. Typescript -> Javascript, Coffescript -> Javascript, ES2015+ -> Babel -> ES5, Sass -> CSS, SCSS -> CSS, LESS -> CSS, Knex -> SQL...

It would be an interesting -- and I think worthwhile! -- project that would use only @apply in CSS files and then transpile them (maybe with SCSS) into the appropriate CSS around the same time you're transpiling all those "$" prefixed variables, Sass functions, and "&" notation. If you want to have a tool that is designed to make @apply px-5 shorthand for padding-left: 5rem;
padding-right: 5rem;
then that would be an interesting tool that wouldn't break semantic structure.

Thread Thread
 
cjpartridgeb profile image
Chris Partridge

I've had the same thought - and it's essentially what I've been playing around with on a Svelte project with Tailwind's JIT mode. All the component markup, script and style tags are self contained in their own .svelte files - using @apply in classes within the style tag.

Certainly makes the mark up a lot easier to reason with when you have a lot of nested elements and many utility classes applied - I won't argue that fact.

The only issues I can see are:

1) Each components generated CSS classes are included in their own style tag within the head element, so I'm not sure what sort of performance issues this might cause if you have a lot of components.

2) Any class used with @apply within the svelte components, gets marked as "used" by Tailwind and ends up being compiled into the stylesheet loaded on the page. So if you don't use those utility classes in the mark up (and only in classes), they are essentially dead weight.

I'm sure neither issue would be difficult to resolve - either way, it's interesting none the less!

Thread Thread
 
mc72 profile image
Mike Ciccone

See, and this is the problem with writing a very opinionated article without understanding it. Tailwind is trying to get you away from using the @apply method. They have mention that in multiple tweets, articles, and videos.

Instead of @apply bg-blue-500 for your brand you can easily set a color theme of "brand" in your config then use your theme in the css. ie:

.button {
background-color: theme('bg-brand-500');
font-family: theme('fontFamily.brand');
///and any other variable you have set in your tailwind config.
}

then you just change your tailwind.config when you need to and you are done. Same as using a sass variable etc. It's not that hard and completely follows a dry principle.

Thread Thread
 
jimkeller profile image
jimkeller

How is this an improvement over CSS variables though? Why not var(--color-bg-brand-500) ?

Collapse
 
geewhizbang profile image
Geoffrey Swenson

A properly designed stylesheet tags an outer element with whatever the thing is. You then can assemble the object, and only light markup is needed for child elements because you can reach in with the stylesheet and control them. I had a job interview where they had "code standards" for doing css where you weren't allowed to nest tags to control them. Everything had to be top-level. Idiotic.

When you are writing code with frameworks, it's easy to use the framework to be absolutely consistent about how the children are constructed, so the markup can be very minimal. It makes it easy to read when the css tags are only used when they actually control some behavior, and they read semantically rather than as named inline styles.

Collapse
 
delanyobott profile image
delanyo {Yokoyama} agbenyo • Edited

Color is not a brand, after all. And that could be a "hack". You don't try to win.

Collapse
 
alukaszew profile image
Adam

It is more examples, that Tailwind will make your project doomed. It's very limited to strictly one style of UI and modifying it can be harder according to project design. Trust me, web development is not only greenfield project with fancy ui.
Sometimes you need reusable components. It's hard to make it with Tailwind.

Collapse
 
kamel3d profile image
Kamel Labiad

He seems to blame the tool rather than using a better methodology for writing a better style

Collapse
 
kerryboyko profile image
Kerry Boyko

But that's just it.

Search and replace will only search and replace based on text strings. Which is great if the only place you use "text-blue-500" is in components you want to change.

That's the thing about utility classes - by definition, they're the same name everywhere you use them. So if you wanted to change "text-blue-500" to "text-red-500" in buttons -- and only buttons -- you'd have to find, and then manually look to see if it's a button before you replace it.

On the other hand, if you have a .button class, or even better, a .branded-button class, you can just change it in one place.

Find and Replace might be useful for changing variable names that are already fairly unique, such as from "my-button" to "branded-button" but it's not useful if you're trying to change, say, only some instances of "float-left" to "float-right".

Collapse
 
jamesthomson profile image
James Thomson

On the other hand, if you have a .button class, or even better, a .branded-button class, you can just change it in one place.

But this is exactly how you should be using Tailwind anyway. If you are applying utility classes all over your html to make your buttons then this is akin to using inline styling. The power of tailwind is that you have an entire set of utility classes that allow you to make small tweaks on the fly because your designer wanted this specific button to have juuuuust a bit more margin-top and be fullwidth at certain resolutions, but you can also continue writing CSS as normal.

I see Tailwind as a utility. It's not there to replace CSS, but compliment your workflow so you can get on with building components.

Anyway, judging by your article and your replies in the comments you've made up your mind about Tailwind and that's ok, but there are many developers that are in favour of it, myself included. Best of luck!

Thread Thread
 
kerryboyko profile image
Kerry Boyko

I'm sure that you could use Tailwind that way, but at that point - why not just use small tweaks in inline styles instead of using Tailwind's classes? Inline styles also have the advantage of being higher CSS priority than class definitions, so you get exactly what you want right away.

But then again, the problem with "if you use it this way" arguments is that they're different from "if you use it as intended." You can see from the Tailwind's own documentation that the intended purpose is to replace CSS.

I'm not saying that utility classes aren't useful. I'm just saying that they shouldn't be used for everything. And they certainly shouldn't need all the tooling overhead that comes with tailwind.

Thread Thread
 
weeklytyped profile image
Weekly Typed

I don't know why you keep saying this is not how Tailwind is intended to be used. The page you linked to is titled "Utility First". I infer that to mean the expectation is you start with utilities, and move to something else if you need it. Practically every word on that page seems to back up that inference.

Further down the page is a section titled "Why not just use inline styles?" which explains what they see as the advantages of utility classes over inline styles. You didn't even acknowledge their reasoning in your article.

The section after that one is "Maintainability concerns". This is where they expressly state that using apply to group styles together is, actually, using it "as intended".

Again, it seems clear to me Tailwind's intention is you would build styles using utility classes first. After some point, they completely expect you to group at least some of those utility classes into a "bigger" class. You seem to think this grouping completely negates the benefits of using utility classes, and that you might as well write it in CSS.

The documentation page that discusses this in particular is Extracting Components.

I'm always wary when somebody says a newer syntax is "hard to read". It's definitely possible to write code that is hard to read. But how can you say it's hard to read when you've spent years training your brain to parse some other syntax. Readibility is subjective with things like this.

For example, I found the example line in your article pretty easy to read. The purpose of md:h-32 and lg:h-64 are actually more obvious to me than the media queries. But I do agree the long horizontal line harder to read. But you don't have to do it that way.

I like your analogy of using single letter variables. But I don't think it's the same thing. These are just short forms of CSS properties. They are clear and documented.

I'm not sold on Tailwind myself. But if your conclusion is that it "provides no value", I don't think you argued it that well.

Thread Thread
 
kerryboyko profile image
Kerry Boyko

I don't know why you keep saying this is not how Tailwind is intended to be used. The page you linked to is titled "Utility First". I infer that to mean the expectation is you start with utilities, and move to something else if you need it.

Eh... If that is your interpretation of Utility First, then I can't fault it.

It wasn't mine, for a number of reasons, but you may have caught me out on an assumption I didn't know I was making.

See, I thought that "Utility First" was referring to a coding philosophy, much like the philsophy of "Mobile First" -- you code for the mobile site first because the mobile site will always work on the full web-page, but not necessarily vice versa.

Mostly, though, the reason why I don't think your interpretation is correct (Start with utility classes, then move away from them) is because almost every example on Tailwind's site is about how you can convert from semantic classes and CSS/SCSS to Tailwind Utility classes. If anything, Tailwind seems to suggest that CSS is a pain point that needs to be resolved and that utility classes are the solution.

I agree that Tailwind might have use with rapid prototyping, but there's no real instruction on how to move from rapid prototyping to final product - You write Tailwind, you distribute Tailwind.

I'm always wary when somebody says a newer syntax is "hard to read". It's definitely possible to write code that is hard to read. But how can you say it's hard to read when you've spent years training your brain to parse some other syntax. Readibility is subjective with things like this.

I remember a similar argument from the author of Clojure about how Clojure (and other Lisp-like languages) were "hard to read." He said: "I don't know how to read German, that doesn't mean that things written in German are hard to read."

But we can admit to ourselves that it is harder to learn certain languages than others, especially for an English speaker. And we can ask questions: Does this have a similar grammatical syntax? Does the language belong to the same family, does it have cognates and loan-words? Does it use the same sounds and tones? Is the alphabet the same?

In the case of programming languages, we can ask similar questions:

  • Does the syntax provide valuable information about what it does? ('height' vs. 'h-', for ex.)
  • Is the syntax internally consistant (Not actually a problem with Tailwind, though PHP suffers from this.)
  • Does it introduce concepts not familiar to other languages? (C's lack of memory safety, Rust's 'ownership', Lisp's Polish Notation, and if you're coming from a dynamically typed language like JS/Python, static typing of TS/C#/Java/C++?)
  • Is it relatively clear to follow the structure of a program written in this language? (CSS is horribly bad at this, as priority order rules can get complex, latter styles overwrite former ones, and of course, there's the !important flag.)

In this case, my criticism of Tailwind being "hard to read" deals primarily on the fact that the syntax is not expressive, and indeeds, chooses terseness over expressiveness. Back in the days of limited memory, sometimes a terse command was better than a long one, we still use "cd" for change-directory and "ls" for "list" in most Unix shells, but no such memory problems were at play here.

It's also hard to read because it's embedded inside HTML, listed horizontally, rather than vertically. Now I'm not saying that it would be as hard to read as if we did styles in PDoublePrime but compared to the default of regular CSS, it makes it hard to read. Additionally, since you're no longer adding your own semantic class names to your HTML, it can be hard to tell by looking at the source exactly what element in the HTML code you're actually looking at when you debug it.

Collapse
 
patricknelson profile image
Patrick Nelson • Edited

Re: @tofraley

… because your designer wanted this specific button to have juuuuust a bit more margin-top and be fullwidth at certain resolutions…

At the risk of taking sides (trying not to as I don’t understand TailwindCSS enough), I will say this: Usually when I encounter situations like this, I’ll bring it up to the designer. When that happens, at least in our case, it’s usually a misunderstanding (but not always). For example:

  1. They have an outdated set of components in their PSD’s, or just out of sync, etc.
  2. They actually intended for us to change this site wide (and not just this one button)
  3. In some rare circumstances they really did this as a one off (and if that’s the case, it’s good to have that clarity so we can built it that way with intent).

Only pointing this out since, on the development side, all too often I’ve found developers simply matching the comps precisely without first ensuring that the change was intentional and (in this case, accidentally) creating one offs that ultimately weren’t really intended. 😊

Collapse
 
pgollucci profile image
Philip M. Gollucci

That's not true, you can use 'primary', 'secondary', etc.

tailwindcss.com/docs/customizing-c...

Collapse
 
ashleyjsheridan profile image
Ashley Sheridan

If you're relying on find/replace tools to make hundreds or thousands of edits to your codebase because of a change like this, it's still a problem. Everyone has seen (or caused) a scenario where a find/replace has gone wrong and replaced the wrong thing by accident, e.g. replacing "Arial" with "ArialBold", but accidentally creating instances of "ArialBoldBold" because your find-fu was off.

However, if the code was following DRY principles, there would be very few instances that needed to be changed, so would be far more likely to be handled better.

Collapse
 
nieuwepixels profile image
Nieuwe Pixels

Not the point though. The point of CSS ,and/or SCSS for that matter, is too make styling more structured. If you need to do mass search/replace that might be a first cue.

Naming it primary, secondary ect. would be a way to go instead.

Collapse
 
raydot profile image
raydot

@Ranieri Althoff, if you have never introduced an error via search-and-replace I salute you for your charmed life as a developer!

Collapse
 
luismartinezs profile image
Luis Martinez Suarez

Damn... I wish we had:

  • Search and replace

  • The ability to use alias for colors, such as text-primary-500

  • The ability to abstract groups of tailwind classes into its own class. For example, with a keyword called, I don't know, @apply or something

Too bad we don't have any of those things and thus obviously by direct deductive argument Tailwind sucks...

Collapse
 
luckynkosi profile image
Nhlanhla Lucky Nkosi

Search and replace still means you’re changing multiple things. More changes mean more chances of things being misaligned and it requires more testing. On an enterprise system, this increases the regression cost.

Collapse
 
tanzimibthesam profile image
Tanzim Ibthesam

Use @apply and use same style everywhere. In react Vue we use components so we can just change style in one Component and it would work elsewhere.

Collapse
 
caliviking profile image
CaliViking

@rsa - I think you have summarized why using Tailwind is a bad idea. You have ended up creating CSS that describes the text color blue, not what you want your style for a particular element to look like.
There may be places where I want to continue using "text-blue-500" in other styles.

Collapse
 
yungifez profile image
Ebuka Ifezue

Lol I've been seeing hate articles with things that are non existent problems

And besides if you are using a js framework or in my case laravel components it's as easy as changing one file

Collapse
 
davidhellmann profile image
David Hellmann

When you have a Button comp… Easy. Maybe variant:red is not a good approach. variant:primary

problem solved. works also for all other comps. Don’t see the problem here from the author.

Collapse
 
robvirtuoso profile image
robvirtuoso • Edited

if only all developers were careful enough to use search and replace responsibly

Collapse
 
mariocalin profile image
Mario

We do we need constant values if we have search and replace...

Collapse
 
imedacf profile image
imedacf

Then don’t use functions at all

Collapse
 
sir_kane profile image
Ahmadou Waly NDIAYE

The author was referring to the number of code changes.
With standard CC, you have to do the change in just one place.

Collapse
 
rubinelezi profile image
Rubin Elezi

Search and replace does not work all the time, as sometime you have to apply logic to it. Maybe you want to update only 763 elements.

Collapse
 
rsa profile image
Ranieri Althoff

In that case, you will still need to go one by one changing the class if you just put "button" in all of them.

Thread Thread
 
kerryboyko profile image
Kerry Boyko

You shouldn't. If the class is .button, and the .button class is only defined once, then one change to the .button class definition in your css should apply to all items that have the .button class.

I should have been clearer in my example by using something like ".branded-button" but you do see how you don't have to go in one by one, right? Because you're not changing what the class is named, only what the class does.

Thread Thread
 
milan090 profile image
Milan

You often create a component for these scenarios, making different button components and reusing them. This pattern follows DRY too and also gives you the tooling and productivity of tailwind.

Collapse
 
redaalaoui profile image
Réda Housni Alaoui

The whole issue with the frontend community, in one comment. Well done.

Collapse
 
ztom132 profile image
Thomas

If only this was possible and such an easy change, you can't replace every instance of this in your app, what if it applies only to buttons/etc.

Collapse
 
alunr profile image
Alun Rowe

You assume you want to replace all instances of text-blue-500

Collapse
 
alukaszew profile image
Adam

Yeah, because everybody want to use find/search every time when the want to change something in all places xD

Collapse
 
quasipickle profile image
Dylan Anderson

A bold article to write seeing as how it seems Tailwind is the starchild of CSS these days. But, an article I think needed to be written. I share most of your views on Tailwind.

I even tried to start a project from scratch using Tailwind because I thought "it's really popular and it looks really pretty - maybe I just need to buckle down and use it". It took me a few days until I came to your same conclusion - why don't I just use plain CSS (or in my case, SASS since I was already using it)?

It seemed silly to write:

.button{
    @apply px-4 py-2 rounded-lg
}
Enter fullscreen mode Exit fullscreen mode

when that's basically the same as:

.button{
    padding: $padding-lg padding-md
    border-radius: $border-radius-lg
}
Enter fullscreen mode Exit fullscreen mode

and yeah - it's a lot less clear exactly what's happening. In my book, clarity always trumps cleverness.

The colour scheme is nice though, so I usually import it into my SASS files.

Collapse
 
jedashford profile image
Jed Ashford

To someone more familiar with raw css, then that's going to be more clear. After using tailwind for a few days that syntax starts to be easy to understand. I'd argue actually much easier to know what happening than long lists of cryptic css commands.

A few:
w-full width: 100%;
w-screen width: 100vw;

container: The container class sets the max-width of an element to match the min-width of the current breakpoint.

How about a simple ring around a component?
Use 'ring'
In css: box-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
ring-inset --tw-ring-inset: inset;

All of this can be done using other libs and dependencies, but tailwind sure makes it easy.

Collapse
 
kerryboyko profile image
Kerry Boyko

Even the things that Tailwind "simplifies" are made more complex, and "ring" is a perfect example.

I'll admit, rings are difficult in CSS, which is why if I need to make one, I usually end up writing my own utility class for it.

But even looking at "ring" you end up having to add 5 classes or more to get your ring styled the way you want it. So "ring" ends up being "ring-3 ring-blue-300 ring-opacity-50 ring-offset-0 ring-offset-red-500" by the time you actually use it.

On the other hand, you could define all those into an actual utility CSS class, call it ".branded-ring" and just use that wherever you need it (instead of having that long string of five classes everywhere in your file.) Or even better, you could write branded-ring as a SCSS variable or a bit of styled component css`` code. If you use a CSS-in-JS solution, you could even have the color of the ring change according to props, giving you behavior control over style.

And it would be more readable, more customizable, and then you don't have to worry about it. You would be able to write it once, and then your entire team could just import your code and reuse it - rather than every developer having to remember how to tailwind-style a ring every time they use that.

Of course, rings aren't that difficult to do, because Google is a thing that exists, and there are a dozen websites which explains how exactly to do it.

Of course, what happens when the CSS spec updates and rings are added due to popular demand? It happened with flexbox. It happened with css-grid. You never know.

Thread Thread
 
thedutchcoder_57 profile image
Reinier Kaper

You can use @apply, which does the exact same thing.
It allows you to make a single class .branded-ring while still leveraging Tailwind's classes.

Thread Thread
 
moopet profile image
Ben Sinclair

You can do that in things like Sass, too. It's not a benefit of Tailwind.

Thread Thread
 
thedutchcoder_57 profile image
Reinier Kaper

But that's the point. It's not a good example of how using regular CSS (or pre processed CSS) is "better" in this case, it's not.

Thread Thread
 
moopet profile image
Ben Sinclair

I'm not sure I follow. I'm saying that having the same feature as an existing build process doesn't make the new one better, it makes it the same. I'm saying that the claim is that BMW make better cars than Ford because BMWs have four wheels.

Thread Thread
 
thedutchcoder_57 profile image
Reinier Kaper

It's not a valuable claim in the original article.

He doesn't like/use Tailwind as he doesn't see the benefit over using what he already does.

That's fine and totally reasonable, but it's not an argument against Tailwind. His whole article is about how Tailwind is useless.

Maybe to him it is, fine, no one argues that. But that doesn't make Tailwind useless in general.

His examples are supposed to show how bad Tailwind is. It isn't. It just doesn't fit him or his way of writing CSS.

Cool, absolutely nothing wrong with that, but again that didn't make Tailwind useless or bad in any way.

Collapse
 
raghavmisra profile image
Raghav Misra

lol same for that last thing

Collapse
 
Sloan, the sloth mascot
Comment deleted
 
kerryboyko profile image
Kerry Boyko

I am coming up with a better solution. Working on it now.

Thread Thread
 
Sloan, the sloth mascot
Comment deleted
 
raghavmisra profile image
Raghav Misra

It's a criticism of an open source project, quite the opposite of a personal attack lol.

Thread Thread
 
tanzimibthesam profile image
Tanzim Ibthesam • Edited

Go and read the full article he attacked people who use Tailwind and expressed judgements. There is difference between constructive criticism n personal attack. everything in this world has pros and cons he could not provide any rationale arguments you can critisize and bash everything and if you think people who are using are fools then make a solution better than Tailwind. Enough is enough he expressed his thoughts I expressed mine I dont know him you dont know me lets lave this.

Thread Thread
 
ashleyjsheridan profile image
Ashley Sheridan

@tanzimibthesam you can't on the one hand criticise Brian for writing an article against Tailwind and demand that he must provide a better solution before pointing out the problems with Tailwind, and then lambast him for doing exactly that.

In the field of development, we should regularly challenge the de-facto ways of doing things, and always be asking if the tool/method/etc is really the best thing to use in a given scenario. It's how the entire industry moves forward. We can question and bring forth discussion about things with articles and posts like this one. You don't have to agree with it, but it shouldn't warrant personal attacks or profanity.

Thread Thread
 
tanzimibthesam profile image
Tanzim Ibthesam • Edited

He has to provide a better solution cause something is called personal criticism and one thing is called bashing and saying everyone is wrong who is using it.He is doing personal attacks and providing negative vibes. Stop defending this silly man. You dont know him and I dont know you or him neither nor he is providing a solution nor people are gonna stop using Tailwind.

Thread Thread
 
ashleyjsheridan profile image
Ashley Sheridan

He doesn't actually have to provide a better solution to anything if he wants to write a post pointing out what he feels are problems with that thing.

As for personal criticism, I can only go on what I saw on this whole thread. This involved him making some points that he felt were issues with Tailwind, and you throwing insults and profanity at him in replies. The only personal attacks I saw were from you. You're right in that I don't know him, I'm fairly impartial in this, although I do happen to agree with his criticisms of Tailwind.

As for him providing a solution (as I've said, he has no requirement to do this, it's akin to a non-driver pointing out problems with a bad motorist, or a non-artist highlighting parts of an ugly painting), he did actually mention he was working on something (and provided a link), for which you attacked him again. Those comments of yours appear to be deleted now, so I can't provide exact quotes, but I believe you did mention his proposed linked solution was a waste of time, bloated, and pointless.

Thread Thread
 
tanzimibthesam profile image
Tanzim Ibthesam

Yup leave it man peace 😂

Thread Thread
 
kerryboyko profile image
Kerry Boyko

Not to re-open this, but I get a smug set of satisfaction from the fact that Airfoil has already been declared "bloated" despite the fact that A) it hasn't been written yet, B) the point of Airfoil is that you only really get value from about 9 of Tailwind's 300+ classes, so why not just write those nine in a way they can be reused and integrated?

I understand putting so much of your identity into, say, a political movement that when someone makes criticisms of the political movement - no matter how valid - you feel personally attacked. But I don't understand how you can do this with a css framework.

Thread Thread
 
raghavmisra profile image
Raghav Misra

Amen

Collapse
 
jedashford profile image
Jed Ashford • Edited

For us web dev isn't massive part of our business and kicking media queries into the dark abyss was satisfying when moving to tailwind.

A few things.

  1. Tailwind-jit solves most of the concerns you listed with chaining, exact colors and values, etc. This should be a must and they're trying to get merged into the main project.
  2. Using Sass, we can compile tailwind into css classes. So you get the best of both worlds.
  3. Even senior devs appreciate anything like tailwind 'container' that does all of the calculations for you. Many of the classes provided are more powerful and easier to use than pure css. Plus you don't need to choose one or the other cause you can use both.
  4. How often are you rewriting styles across your website that you must have global css? Any of that is already externalized to the tailwind.config file. I've never rewritten a site/pages without having to start over with new html and css. Just comes with a redesign.
  5. Media queries are a thing of the past. So many abstracted queries across the project. min-width? max-width? Which way does that go again? Not explicitly defined in the html, so you're left guessing often why your css changed. All these queries are gone often with a simple sm:flex class and it lives with the html it alters. This is by far the most powerful and follows the proximity principle of development.

I wish you luck, always fun to learn something new and see how the community can alter development.

Collapse
 
kerryboyko profile image
Kerry Boyko

Interesting.

I would say that even if web dev isn't a massive part of your business, then why would you want to deal with Tailwind anyway? You're not really skipping out on the bulk of complexity of CSS, you're just writing CSS using an alternative syntax that maps 1-to-1 to actual CSS. It doesn't make it any easier.

Compare that to something like Bootstrap, which does make things like breakpoints, media queries, etc. easier. Yes, it's more opinionated, and "bootstrap sites look like bootstrap," but if web dev isn't a massive part of your business, then that's all you need.

And while you can compile tailwind into CSS classes (with either Sass, as you mention, or @apply) -- why would you want to? Why not just write the class directly, skip the middleman?

As for "container" - yes, it's easier to write 'container' than it is to fix max width at all media queries... the first time. But once you've done it once, it's easier to reuse. Now, if Tailwind were just a collection of commonly used CSS utility classes, I'd say that it has value, but "container" is a massive exception to the rule. 99% of tailwind is just one-to-one mappings of CSS properties.

In fact, I'd be surprised if someone hasn't written a very stripped down version of Tailwind that is just a single CSS file with "container" and one or two other cherry picked utilities. If they haven't, I might write it myself.

How often are you rewriting styles across your website that you must have global css?

I work at a consultancy. The answer can be "very," depending on the client's whim. But aside from that, the main reason I might rewrite a style is because it's a bug fix, and in that case, I'd rather have to fix the bug in one place rather than fix it in 100.

Media queries are a thing of the past.

Yes, but it's not like Tailwind invented the 760 grid system. If all you want is to avoid writing media queries everywhere, there are already tons of great libraries for doing that.

My problem isn't that there aren't some examples of good code out there in Tailwind. My problem is that it's 99% bad code, and the 1% of good code has been done, better, elsewhere.

Collapse
 
ndimatteo profile image
Nick DiMatteo • Edited

The answer to virtually all of your complaints is extracted components.

Let's address your complaints one by one though:

It's WET, not DRY.
Not if you use extracted components.
You have a wrapper class you like to use a million times? Great. Extract it! Then you only have to edit it once to update everywhere. Still DRY my dude.

HTML should only concern itself with the structure of your page, not the styling of the page.
These are inextricably linked though. Ever use a modifier class to change how your component appears? Where is that going? In your HTML.

Know what modifier classes are eerily similar to? Utility classes.

For example: need to stop page scrolling when a modal is open? Rather than writing a new class to do that, just use the overflow-hidden class already at your disposal.

It's hard to read.
I totally agree! ...So use extracted components.

Now you can write your html with a simple class like card, and then go to town in your CSS with:

@apply relative p-4 rounded-sm ...;
Enter fullscreen mode Exit fullscreen mode

You lose a lot of the features built into standard CSS
Not true. Again, use extracted components.

It solves a problem that doesn't exist
At this point it should be obvious the problem it's solving, but just to clarify: it makes writing CSS easier and modifying your components in a logical way. Meaning, less time writing out individual css properties and values.

You want to see an obvious problem it solves?

I want a box to fill it's container, according to you I should just write plain CSS like so:

.box {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}
Enter fullscreen mode Exit fullscreen mode

5 lines of CSS I have to write or copy/paste from somewhere. And if I want to update the positioning to be 1rem in on each side? Now I have to update 4 lines individually.

Not with extracted components:

.box {
  @apply absolute inset-0;
}
Enter fullscreen mode Exit fullscreen mode

If you want better than CSS, there are already solutions.
All of the solutions you mentioned don't make writing CSS any easier. You mention CSS-in-JS solutions, but that goes against your argument that styling shouldn't be in your HTML and you mention BEM/SMACSS but that's just a writing convention.

It literally provides no value, and tons of problems.
There is massive value in efficiency. If you want to write code faster and keep your stylesheets lean, there is plenty of value in something like Tailwind.

And I say this as someone who up until 6 months ago, refused to try out utility classes for similar hesitations. But instead of writing a big long post about why I think it's useless, I gave it a try and found a way to fit it into my workflow in a way that has allowed me to speed up my development time and still create accessible codebases for new developers (extracted components still live alongside regular CSS).

BONUS: nowhere did you mention the treeshaking capabilities of tailwind. If you're managing large-scale sites with massive style guides and you care about bundlesize, that alone is a benefit of Tailwind that I'd find it hard for anyone to argue against.

As an aside:
Personally, I don't love when people use a platform like this, where lots of newcomers to our industry frequently look to for answers, voice an ~opinion~ that borders on condescension about something that they don't seem to fully understand.

It's ok to have an opinion, or prefer different tools, but if you don't like something or don't understand the value, you don't need to pull a Tucker Carlson (???) response to it.

Mic Drop

Collapse
 
moopet profile image
Ben Sinclair

Ever use a modifier class to change how your component appears? Where is that going? In your HTML.

Yes, I've worked places where we do this. But I've also worked places where we use Bootstrap, and they're both bad ideas as far as I'm concerned. I don't think we should use modifier classes.

Collapse
 
ndimatteo profile image
Nick DiMatteo

Who said anything about Bootstrap? I'm also very curious what you're doing instead of using modifier classes to style variants. Are you just writing inline styles? Duplicating other class styles to create a new class just to avoid this?

I guess everything else I pointed out you don't feel like addressing? It's pretty clear to me that you aren't interested in wavering from your original "opinion" here.

Best of luck navigating this industry with that mentality.

Thread Thread
 
moopet profile image
Ben Sinclair

Who said anything about Bootstrap?

I did, me. What I'm saying is that I've worked places where we've used Bootstrap, which uses modifier classes and does basically all the things people criticise about Tailwind. Just because I've worked somewhere that does it a particular way, and where I go along with it because it's my job, doesn't mean I approve of something. So yes, I have and still do use modifier classes, and no I don't think they're the right approach.

very curious what you're doing instead of using modifier classes to style variants

Writing semantic HTML. Where there's an absolute client requirement to do something non-semantic, then adding classes beyond the semantic, but pushing back against it.

I guess everything else I pointed out you don't feel like addressing?

Everything else you pointed out was something I (mostly) agreed with.

Collapse
 
jackmellis profile image
Jack

I'm not sure why tailwind is so divisive, I've not met anyone who thinks it's "okay", we either love it or hate it.
Personally I love it and here's why:
I've always hated external css files, or one monolithic global css file. Looking at some html and then spending 5 minutes trying to work out what ut looks like was always frustrating. Sometimes SoC isn't a such a good thing. You mention Vue, but Vue's SFCs were actually made to increase the coupling of your html/css/js!
You can't do media queries with inline styles.
Tailwind let's you abstract your units. This is one of the biggest pros for me. I can use a class like p-3 in multiple places, but if I decide I want bigger spacing, I can just update my tailwind config and all of my p-3 elements will update. You mention colors, but these are just tailwind's defaults. In reality you would configure tailwind to have primary and secondary colors, e.g. bg-primary-light. Then when your cpany decides to rebrand, it's super easy.
If you don't like how you end up with super long class names, there are simple solutions. I use a simple concat library to split my classes into multiple lines. I group my classes either by breakpoint or by area (like all flex related classes) and it's really readable.
On the same topic, if you're using something like react tailwind should actually encourage you to make more components. All of my tailwind classes are neatly tucked away in low level components. My application level components are incredibly terse and have no styles or classes on them.
But the biggest win for someone like me, is I can just "get on". I don't have to worry about coming up with BEM names, or where to locate my styles, or how to keep spacing consistent, or compiling sass. I can work on the stuff I love (functionality) with the confidence that it will look good and consistent.

That said, I get a lot of the reasons people don't "get" it. But if you were to join my team I'm afraid you'd just have to get over it! 🤣

Collapse
 
kerryboyko profile image
Kerry Boyko

I get it.

I honestly think that Tailwind might be a good fit for you and your projects at this time.

I actually think a better fit might be a more opinionated framework, such as purecss.io/ - but forget that for right now.

If you are designing websites as a secondary consideration, if you're not comfortable with CSS, if you just want to "get on" with your structure and behavior, then maybe I can see it. In this type of scenario, I could see how Tailwind might be used as a rapid prototyping tool to try out different designs, but that once a design is settled upon, Tailwind code is rapidly stripped out and replaced with a more scalable, maintainable solution.

If I were to join your team, yes, I'd get over it. I'm a professional - if my team lead were to go with Tailwind, I would explain my concerns, state that I believe it to be a large mistake, but at the end, follow the team lead. That's what you do. Make your case to the guy who makes the call, then follow the call.

But if I was team lead, and one of my experienced senior engineers were telling me that a framework I was considering was completely worthless and would generate tons of technical debt for no appreciable value, I'd at least pause and think about what he was saying before plowing ahead.

Collapse
 
jessegavin profile image
Jesse Gavin

It literally provides no value, and tons of problems

I started writing CSS for money in the year 2000. I am very familiar with CSS and all the different ways you can use it, LESS/SASS/BEM/SMACSS, etc.

Tailwind provides a lot of value and solves tons of problems for me. I've been using it for about a year on a large Vue project. It's been really great.

You can always supplement it with hand-written CSS. Sure it introduces some problems (like anything else), but the benefits far outweigh the cons.

Collapse
 
sparkalow profile image
Brian M.

I love tailwind. I love the absolute tiny css file that goes along with it (when purged). I love that my boss will not mess up the rest of the site by editing a css style for his pet project page. I love not having to invent names for css classes. I love extracting tailwind classes to re-usable components.

Collapse
 
kerryboyko profile image
Kerry Boyko

I love that my boss will not mess up the rest of the site by editing a css style for his pet project page.

You have bigger problems than I can deal with here.

I suppose in some cases, tailwind would be an improvement if your boss can go in and edit your company's css file for a project page. But then we're not exactly talking about best practices, are we?

Collapse
 
sparkalow profile image
Brian M.

You can replace the word "boss" with "others".

Thread Thread
 
kerryboyko profile image
Kerry Boyko • Edited

Still doesn't change the problem.

It seems like the problem is one of scoping, and tooling though, now that you mention it.

First, it seems like you're editing a global .css file. Now, whether it's SCSS, CSS Modules w/ a bundler (Webpack? Rollup?) it's... rare these days for there to be one universal CSS file precisely because web development has gotten much more complex. The output might be a single CSS file - that's the point of a bundler after all - but the input shouldn't be.

One of the key things you can do with CSS (and it's even easier in SCSS) is to introduce scoping.

So, let's say that you have a pet page.

All you have to do is, in the root of that pet page (whether it's

or or whatever...) is add )

You can then write styles that apply only to that pet page.

/* CSS */
.pet-page h1 {
    font-family: Lobster, Comic Sans, Sans;
}
.pet-page h2 {
    font-family: Lobster2, Lobster, Comic Sans:
}
.pet-page .call-to-action {
    color: pink;
    border: 3px dotted pink;
    padding: 5px;
}

It's even easier in SCSS

/* SCSS */
.pet-page { 
  h1 {
    font-family: Lobster, Comic Sans, Sans;
  }
  h2 {
    font-family: Lobster2, Lobster, Comic Sans:
  }
  .call-to-action {
    color: pink;
    border: 3px dotted pink;
    padding: 5px;
  }
}

This is the power of CSS Combinators, one of the things you lose with Tailwind.

Thread Thread
 
sparkalow profile image
Brian M.

Sorry, I guess I should have been clearer. I understand scoping, components and most modern css best practices. I used to do agonize over all that with sass/less/postcss - code splitting across files where it made sense, components, namespace scoping, BEM and other methodology experiments. All with some form of build using npm/gulp/grunt/bundlers/etc. Now we just tailwind and don't really need the other stuff. It works great for our team.

Collapse
 
jacobherrington profile image
Jacob Herrington (he/him) • Edited

It's sort of ironic that the site this is posted on took inspiration from Tailwind in our own approach to CSS!

I got a whiff of it and quickly learned the name is appropos: it was as welcome and useful as passed gas.

It's entirely possible that was actually me. I produce a potent musk.

It literally provides no value, and tons of problems.

I respectfully disagree! Personally, Tailwind solves a lot of problems for me. For one thing: CSS is magic and I refuse to listen to anyone that thinks they can explain it to me because I might get hexed in the process. A tool like Tailwind keeps me safe from the dark arts (this is why I always burn sage when talking to @pp).

More generally, I think critiquing Open Source tools for their issues is fair (especially if those critiques are attached to a PR!), but we also have to be mindful of the limits of our own perspective.

As a CSS or front-end expert with a team of engineers to back you up, Tailwind might not be the best choice, but that doesn't describe all of us. When I build a landing page for a charity organization (I'm not billing, I can't handcraft all the CSS for this thing), I'm definitely using Tailwind or something quite similar. Tailwind is a great solution for those solo indie hackers out there; it improves productivity and abstracts a source of complexity that not everyone has the time or aptitude to dive into!

Another way to phrase it: more or less these points would also apply to Rails or Laravel, but those frameworks solve a lot of problems.

If so, why are we considering replacing CSS with something that does less, is more complex, creates bad quality codebases, and possibly ends up with massive vendor-lock in down the line?

I'm not sure anyone wants to replace CSS with Tailwind! That sure is some all-or-nothing thinking (I learned about that in therapy, hell yeah)!

You use the example of Assembly and C, but I think this is more like C and Ruby; I'm not a C developer, as much as I try to learn about it, but I can build some pretty cool stuff really quickly with Ruby. Of course, the stuff I build in Ruby is going to have some weaknesses for having used that abstraction, but if I didn't use Ruby I probably wouldn't ever get the code to compile anyway.

However, I can go ask some friends who know C or Rust or something similar to extend my Ruby code when it really needs that performance boost!

Maybe one day, I'll have to re-write my Ruby, but that's a problem for millionaire Jacob. He has more users and paying customers than his little Ruby app can handle.

Tailwind doesn't stop you from cracking out that hellish CSS abomination whenever you want! When my Tailwind implementation makes something difficult I'll hire a warlock to summon whatever void-being we need to fix my layout.

While we disagree, I'm glad we can have a discussion about it. Maybe you're right; if people find this article searching for more context around Tailwind, they will find a lot of opinions (and the strong stench that comes with a multitude of opinions).

However, for now, I think the enlightened 21st-century philosopher-king Jason Mraz penned it more directly than I can every hope to: "You do you and I'll do me."

Collapse
 
alexanderjanke profile image
Alex Janke

Oh boy did you get some reactions to the post.. I totally haven't read all the comments so I might just rephrase some other comments in my own words and maybe add my own two cents while I'm at it.
First of, don't use apply. Don't. I'd deny any pull request using @apply. Horrible feature. Yuck.

From skimming through the comments I didn't see the point of standardization though. You can ignore all extra work of making sure all your devs in your team use the same kind of class-namings. To BEM or not to BEM, all these decisions go out the window, reducing extra time needed in planning that is better used to actually get to work.

The example you have in your section "It's hard to read":
How are they any different if you put the code into a component? All tailwind really helps me with is to not get fuzzy and build my own broken diy-css-framework over the time. It stops me from doing stupid things like getting into the habit of writing bootstrap-esque classes á la .card .card-title .card-body and so on. Instead of writing several classes myself now I write more components and think about making my project more modular, increasing reusability while maintaining a single source of truth. Now you might say "but I can have a source of truth too in my .css file". Sure. But why would I go through all the hassle and time to slowly write all the css classes myself that are literally right there from the get-go?
Convenience and maybe a good portion of laziness? Yup, absolutely.

I'd probably just don't use it if there is some crazy specific task from a client where you can see right away that you're going to rewrite 90% of the tailwind config anyways. Overall it's just crazy fast to get websites done with tailwind while staying consistent in your markup, especially in prototyping stages.
So all that's left is probably to look at it by a case by case scenario and decide what tool to pick for the job. As always.

Collapse
 
kerryboyko profile image
Kerry Boyko • Edited

First of, don't use apply. Don't. I'd deny any pull request using @apply. Horrible feature. Yuck.

I agree. Not that I don't think you shouldn't bundle related CSS properties together into reusable classes, but that the whole point of Tailwind is to avoid that type of composition altogether. I may not agree with Tailwind's philosophy, but I don't mind pointing out as part of it's criticism when it's being philosophically inconsistant.

You can ignore all extra work of making sure all your devs in your team use the same kind of class-namings. To BEM or not to BEM, all these decisions go out the window, reducing extra time needed in planning that is better used to actually get to work.

Weirdly, "making sure all devs use the same class namings" is not really a concern that I have. I mean sure, it's a good thing to aim for, but it's only really a "must have" if you're using an unscoped global .css file for styling. Most of the work I've done has been in Vue or React; which means I'm either using Vue's <style lang="scss" scoped>, CSS Modules: "import 'myComponentStyle.scss", or CSS-in-JS: "const myComponentCSS = css\" (which probably won't show up right because of markdown not interpreting backticks

I suppose if your team is operating on one big global .css file (instead of using CSS modules or CSS-in-JS) you have to make sure it is using the same naming conventions.

But for the most part, it's more important to me that class names are unique and descriptive of content rather than follow a certain format, so that they can be easily searched for in the source code of the finished HTML (for debugging) or understood by the rest of the developers on the team.

One of the patterns I'm seeing is that people who really seem to like Tailwind point out how much more useful it is than CSS, and don't seem to have a whole lot of experience or willingness to try CSS-in-JS or pre-processor (SCSS) solutions.

It stops me from doing stupid things like getting into the habit of writing bootstrap-esque classes á la .card .card-title .card-body and so on.

I have no problem with utility classes, used sparingly. Ideally I'd prefer SCSS mixins or resuable CSS-in-JS code compared to them, but what's wrong with that?

mixin card {
  &.title {
    /* css */
  }
  &.body {
    /* css */
  }
}
.recipe {
  @include card;
}
.captioned-photo {
  @include card;
  & img {
     /* css */
  }
}
Enter fullscreen mode Exit fullscreen mode
<div class="recipe">
  <div class="title">title</div>
  <div class="body">body</div>
</div>
<div class="captioned-photo">
  <div class="title">title</div>
  <img src="foo"/>
  <div class="body">body</div>
</div>
Enter fullscreen mode Exit fullscreen mode

But why would I go through all the hassle and time to slowly write all the css classes myself that are literally right there from the get-go?

This is a compelling argument for a framework like Bootstrap, but not one like Tailwind.

One of the problems I have with tailwind is how many of it's classes - something like 99% -- though I haven't done the actual math, I'm pretty sure that's the right ballpark, give or take 1% -- are just one or two lines of CSS.

"p-8" is just "padding: 1.5rem;". "rounded-full" is just "border-radius: 9999px".

I did go through and identify about nine tailwind classes (out of how many hundreds?) that DO actually provide some convenience and am rewriting them in my own utility class library.

Overall it's just crazy fast to get websites done with tailwind while staying consistent in your markup, especially in prototyping stages.

By all means, prototype away, but I wouldn't recommend it if you're dealing with end products meant to be delivered to the product owner.

Collapse
 
alexanderjanke profile image
Alex Janke • Edited

I honestly don't use it as much as my text might suggest but I can see the appeal and tried to find some points to make you maybe see them from a different point of view :D

but I wouldn't recommend it if you're dealing with end products meant to be delivered to the product owner

This caught my eye because I honestly never worked in a situation where I hand over code to another owner and I mostly work on internal products. The rare SaaS things I worked on were in good ol' SCSS though.
What would be interesting to see is the type of projects people work on using Tailwind. Is it a lot more agency-type of projects, internal sites (as in admin tools) or SaaS?

Collapse
 
3200pro profile image
3200pro

I've been writing CSS since 2000. I love the way tailwind works. It's especially nice for modern website development. An agency owner I collaborate with just mentioned that he appreciates it because it unifies the frontend style of a website while allowing junior developers very strong documentation on the style guidelines.

Everyone out there reading this that loves TailwindCSS checkout TailwindUI! I've been using the newly released React Components on my Gatsby websites and it's awesome. Super seamless, super optimized, and it's very fast to build out components.

Collapse
 
amberpython profile image
amberpython

I actually start using Tailwind from TailwindUI with React, that's where I got the bad developer experience.
It is ok to use tailwind UI as a whole component. but if I want to make changes to it, I have to read through hundreds of lines of html with really long classNames. the problem of tailwind is that it enable ppl not to think about components, which makes readability really bad.

Collapse
 
3200pro profile image
3200pro

I'm going to have to disagree. Unless you are trying to use it without purchasing them.

The site has HTML showcasing the components on the frontend if you aren't logged in. If you purchase TailwindUI there are React versions of the components.

*Example:
*

export default function Example() {
return (
<div>
<label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900">
Email
</label>
<div className="mt-2">
<input
type="email"
name="email"
id="email"
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
placeholder="you@example.com"
/>
</div>
</div>
)
}

Thread Thread
 
amberpython profile image
amberpython • Edited

I am talking about the full version of tailwind ui. take the pricing section for example, the three tiers component has poor readability. i cannot tell by a first glance the structure of the component. What I am trying to say is tailwind enable developers to write code like this. When I work in a team, it happens. The example is functional and performant, but it is not readable. If we are using styled component, for example, it will force the developer to carefully decide the components in that pages first, then we will see things like <Title/><PriceCard/><CardWrapper/><CardTitle/><PurchaseBtn/>, which will show the structure clearely.

Collapse
 
tanzimibthesam profile image
Tanzim Ibthesam • Edited

Lets wrap this discussion I am not sorry to this guy cause everything has its pros and cons but this guy could not provide rational argument in most cases.
Why do we use framework because it eases our lives we could have just used Vanilla Javascript.
Tailwind should be compared with Bulma Bootstrap and not with saas which i believe is a mess too and not a css framework and some like it. While Tailwind has some cons it is definitely solving problems for many and many are buying premium version I even dont own one.
The way he bashed Tailwind we can also bash React Vue Angular and everything that exists.
But if someone is using it let them use it rather than spreading negative judgements.
This post was like begging people to not use Tailwind with mostly irrational arguments and most people who agreed I believe never made a full project with tailwind I understand they have their own preference .
In return this post just gained negative publicity which at times is good for a brand.
Bottomline nor people who need to use Tailwind are not gonna stop and neither the guy will provide an alternative solution.
But if you ever bash a technology mention a few good sides and atleast have minimum respect to people using it.
I am not replying anyone to this comment and I have deleted all my comments previously. Remember onething dont always see the world through your eyes a product might seem bad to you but its provides solution to others and people are making money. Everyone stay fine stay safe tc.

Collapse
 
vaviloff profile image
Vaviloff

Immense thank you, @brianboyko !

So glad articles like these start to be written, providing simple and precise explanation of what is wrong with Tailwind.

My personal a-ha moment came after inheriting a project with it. It was supposed to be a no-brainer, after all you don't have to learn someone else's home-made CSS framework with Tailwind (they say)!

<!-- nope nope nope nope -->
<nav class="absolute lg:relative lg:flex lg:text-sm bg-indigo-darker lg:bg-transparent pin-l pin-r py-4 px-6 lg:pt-10 lg:pl-12 lg:pr-6 -mt-1 lg:mt-0 overflow-y-auto lg:w-1/5 lg:border-r z-40 hidden">
    <li class="ml-2 mb-4 flex">                    
        <div class="hover:cursor-pointer text-white lg:text-indigo-darkest no-underline font-medium mobile-home-trigger"></div>
    </li>   
</nav>
Enter fullscreen mode Exit fullscreen mode

Yeah, lg:pl-12 lg:pr-6 -mt-1 lg:mt-0, give me home-made CSS frameworks any time instead of this mess.

Collapse
 
geewhizbang profile image
Geoffrey Swenson

Bootstrap and Material Design are also both utter messes of applying way too many tags to way too many elements. I prefer to write my own cleaner more terse styles. Tailwind just is even worse but I haven't had to use it thankfully.

With this kind of overelaborate markup the stylesheet turns into a gawdawful warring mess of !important and even worse ng-deep messing up other devs pages especially because the backend devs that big companies tend to hire to do front end work seem to be incapable of using their own elements, creating simple reusable styles, or cloning well done markup from other pages and think that building a page is sort of like assembling tinkertoys without having to concern themselves at all with the messy art of design.

Collapse
 
archonic profile image
Archonic

If you're non-stop appending classes to get what you want, then sure, it can be a bit messy. I've found Bootstrap + a small amount of custom css with @extend to be great. I started making sites like that in 2012 and haven't looked back. Rebranding is super easy just by changing some variables and fonts.

Collapse
 
geewhizbang profile image
Geoffrey Swenson

In my last project idiot devs were using Bootstrap and Material design tags for different purposes on every page. It would have been better for the project if someone that actually knew what they were doing had written simpler styles and templates for all the common elements and they were almost always overriding things with the stylesheet many times with inline styles for all the framework items they were misusing. Every single page had elements common to other pages that were laid out differently and badly.

I was the only one in the entire project that was writing comprehensive reusable styles and using for loops for repeated elements and I was making some headway in that the clients were liking my pages and not so much the dreck they were doing, but I got fed up about the massive unpaid overtime and took a different job. I still think bootstrap and Material design are barking up the wrong tree. They are too complex.

As an example I just started a project in VueJS 3. I needed controls so my first library that I tried had utterly beautiful looking controls but when I installed it the compiler warned me that it was making my bundles too big. And looking further it was a big camel designed to get its nose into your tent and then force you to pay $900 per developer to use a designer tool they wrote to handle the massive complexity of the whole thing.

I found a open source implementation of the multiselect I needed written in native Vue, with maybe 80 simply named css styles only 8k gzipped, easy to modify without a tool, which is the right way to build things.

Thread Thread
 
archonic profile image
Archonic

Any framework can be abused or misused through laziness/ignorance. I think plain CSS is actually the most susceptible to abuse. Freehand tools are the most flexible but with no standard laid out, most people will just end up making a huge mess over time.

I understand the argument that Bootstrap is heavy but it's only JQuery that makes it heavy and BS5 will get rid of that. If a project doesn't need a component, just don't include it. Perhaps I have heart shapes glasses because I prefer a standardized look and feel over something unique but I'm going to keep reaching for standard libraries that let me get a front-end done in days instead of weeks.

Thread Thread
 
geewhizbang profile image
Geoffrey Swenson • Edited

I still think Bootstrap is a stunningly awful POS. I have been forced to use it on three projects now, loathe it. I can write my own stylesheets way better. There are a few good ideas in there, such as the font icons, but the whole idea of putting ten tags on every element and the idiotically meaningless names of the grid controls can just go somewhere the sun doesn't shine. It doesn't save you time, it makes things harder.

I create my own standardized look and feel.

All of the projects where I loathed Bootstrap were using modern frameworks. It has nothing to do with jQuery, it has to do with the terrible metaphors Bootstrap uses.

Thread Thread
 
archonic profile image
Archonic

Strong words. You aren't forced to use 10 classes everywhere. You could come up with one class which extends those 10 classes and then use one repeatable class, same as any compiled CSS. I think of BS and all the other frameworks as just time-saving utility and for me it's always done a good job of that. I don't honestly know how it could possibly make things harder unless your always overriding it, which is a miss-use.

Thread Thread
 
geewhizbang profile image
Geoffrey Swenson

I wasn't the one overriding it. But the stylesheet was a mess of overrides nevertheless. I've never seen anyone compile the Bootstrap classes into one class, they were using them everywhere with multiple classes on every object.

The problem is that it becomes very difficult to see where some unwanted style attribute comes from. I also don't even want to understand how the grid classes work, because the names don't make any sense whatsoever.

What I really can't stand is how large companies hire back end developers that think that using a CSS library like this is a substitute for actually writing a well conceived ui. They pile on the various containers and objects and get something hugely inconsistent with layout anywhere else. I have written very large applications, and I didn't need a third party library to do it. I have in the past copied just the bootstrap style icons into a project but not used anything else from it. It's a style of markup I strongly disagree with.

Collapse
 
markgoho profile image
Mark Goho

@brianboyko thank you so much for writing this article -- especially the part where you talk about why you wrote it. Additionally, while most folks won't read through all the comments, it shows an incredible level of dedication when an author takes time to read (not skim) comments and provide thoughtful responses.

Apologies in advance for this very cynical and bleak perspective....

While most of your article focused on technical reasons why Tailwind would not be a wise choice for most projects, I thought it might be helpful to at least call out why Tailwind is so popular in the first case: a lot of developers don't really know CSS, and they don't really care. Tailwind promises to make CSS more accessible for those developers. Unfortunately, I think a lot of your points above (which resonate with me, someone who knows CSS) just don't make sense to developers that have no strong desire to become proficient with CSS.

Why would these folks care that @apply isn't in the CSS standard? They're told to use it by the Tailwind documentation and that's really all that matters.

You make a great point about not being able to use combinators, but (really) who among these developers were ever going to use combinators anyway?

Let's be honest: Tailwind is for developers that don't know and don't care to know CSS. Tailwind is for developers that want to pretend they use CSS.

This is very similar to the extreme dependency on a grid system for layout when CSS Grid exists, is infinitely more powerful, and can be picked up in a weekend of study. Call it laziness, willful ignorance, or mediocrity, but Tailwind is popular and will probably remain so as long as developers don't want to do the work of learning CSS.

Collapse
 
sagalbot profile image
Jeff Sagal

Great take Mark. Had a good chuckle!

Your perspective is neither cynical or bleak, but it is incredibly condescending and presumptuous, even more so than @brianboyko 's very condescending and presumptuous piece, so props on upping the bar! 🎊

Collapse
 
alex_layne_3bbfe310a34ac7 profile image
Alex Layne

I do know CSS and I also absolutely hate reading it. The reason I love Tailwind is that everyone writes CSS differently and with Tailwind you can’t do that. No more reading through an inscrutable CSS file, flipping back and forth from the HTML to figure out what the hell it’s actually doing. People don’t like Tailwind because they’re ignorant of CSS, they like it because in many cases it’s a better experience for both writing and reading it.

Collapse
 
assertchris profile image
assertchris

Having read the article, I disagree with some of the statements and find others to be factually inaccurate.

Things I disagree with are mostly summed up in this part: "If you choose Tailwind for a mission critical application, you will end up making your job harder, your application more brittle, and your team, in the long-term, will suffer."

I have not (anecdotally) found this to be the case. I maintain many applications that use vanilla CSS, many that use styled components + react, a few that use SCSS, and many that use Tailwind. I have not found apps that use Tailwind to be more brittle or cause me or anyone else in my teams to suffer. I do not see any evidence to support this statement.

This that are factually inaccurate:

  • "You can't chain selectors together" You can. See: tailwindcss.com/docs/hover-focus-a...
  • "Now you have to go through each component and manually change..." No you don't. See: tailwindcss.com/docs/customizing-c...
  • "...explain what's wrong with Tailwind, but it really is a 1-to-1 mapping" No, it's not. You can't apply classes responsively in inline styles. You can't use

Some comments may only be visible to logged-in visitors. Sign in to view all comments.