> The more features that get added to Tailwind, the more you have to know about CSS before you can use those features. Right? So why not just bite the bullet and learn to use CSS without the additional tooling (and weird, often lengthy additions to your HTML) that Tailwind and other utility-first styling frameworks require?
This misses the point of Tailwind entirely. The point of Tailwind is to give everyone a common vernacular of CSS phrases so that I can bust out something like "p-2 m-2 border-red" super fast and still be writing code which is immediately comprehensible to everyone else on my team. There's also the benefit that I no longer have to think about class names, which is shockingly large.
Using CSS does not give you that. I don't even address the "learn to use CSS" phrase because anyone who uses Tailwind obviously knows CSS! We do the translation back and forth in our head as necessary.
It's also why I'm not concerned about Tailwind getting more features:
* Tailwind needs to have all the features of CSS, otherwise it's incomplete.
* The notion of Tailwind being "bloated" makes no sense:
* The Tailwind compiler eliminates any styles you don't need.
* Tailwind stylesheets are always going to be much smaller than normal CSS for any decently-sized app.
> Using CSS does not give you that. I don't even address the "learn to use CSS" phrase because anyone who uses Tailwind obviously knows CSS! We do the translation back and forth in our head as necessary.
While I agree, sometimes I feel Tailwind users forget that writing regular CSS is also an option. I have seen examples where developers repeat Tailwind classes for every paragraph, every link. They repeat same typography styles over and over again instead of creating some base CSS. A great example is this checkbox[1] where developers used 71 Tailwind classes to style the input.
I think Tailwind only shines alongside a component system like React where you can just create a new Paragraph tag and reuse that. It makes me very happy because in the end there's way less code for me to read and understand, and changes are obvious, immediate and easy to do.
By "base CSS" are you referring to using @apply? That's generally not recommended from what I understand, with componentization and reuse being preferred over most usages of @apply for this purpose.
I feel us programmers should be open to breaking rules in favor of convenience. I don't see an issue to why you can't use `p:not(:first-child) { margin-top: 12px; }` just because you're using Tailwind (that particular rule gives a margin to every paragraph except the first one which is usually needed in articles). The most productive programmers I have seen frequently disregarded best practices if it suited the situation.
I tried to avoid using @apply but that makes creating variations (e.g. of button styles) REALLY hard — as your code is just littered with class names. Plus if you're adding :active :hover and :focus styles, you have to do it on ALL the variations on all of the pages. It's frustrating and takes a really long time.
I've moved to using @apply in a few generalized classes and I love it, since my class names like "btn" "btn-success" "btn-success-outline" describes what I want, and I can easily go in and change them.
I'm not creating a new component for every tiny thing, like a button or a link, just so I can avoid using @apply...
> I can bust out something like "p-2 m-2 border-red" super fast and still be writing code which is immediately comprehensible to everyone else on my team
Is this somehow not possible if you say “padding: 2px, margin: 2px, border: 1px red solid”?
You would have to adjust for the default units in Tailwind for the padding and margin: "padding: 0.5rem, margin: 0.5rem"
In practice, GP wouldn't use "border-red", they'd use a shade of red (border-red-100, border-red-200, etc). The higher the number, the darker the shade.
These defaults are an underrated feature. The defaults for spacing ensure things look cohesive, and the defaults for color are supposed to harmonize well. They're informed by the book Refactoring UI [https://www.refactoringui.com] to ensure your design has structure. They're designed to make it easy to adjust parts of your design, without guessing, when things look "off".
thing is this is way too easy for developers only focused on frontend development.
for us backend developers also doing database, caching, networking, storage, etc. being able to write "m-2 p-2 border border-red-600" is way easier to remember and doesnt take that much brain cpu cycles that we reserve for more important stuff.
They are not the same. Margins and paddings can be configured to use a different base size (5px instead of 0.25rem). Colors can be configured freely, and with a centralized config. Kinda like inline Strings vs constants.
But there‘s more important benefits (IMO):
- Media queries are done inline and become ridiculously easy to read
- Light/dark mode colors and selectors are done inline
- Gradients are easy as pie and actually readable
- Built in grid system
- Your code is somewhat future proof - if the idiomatic code for a gradient changes, you only need update your Tailwind version
When you declare `py-4 px-2 bg-blue text-white rounded-lg` on five buttons in a row, doesn't this work almost exactly like inline strings when you compare to the semantic classname `button-secondary` that is maintained in one single place much like a constant? And wouldn't you just rely on constants to maintain consistency between components, in other words use CSS variables?
Edit: Hacker News did of course inline it, but that only proves the point.
The same goes for light and dark mode. These are by the way Custom Media Queries [1], but Tailwind has a `@screen` directive much to the same effect.
Gradients aren't much different in CSS nowadays, really, and the "built in grid system" is really just a super inflexible subset of CSS Grid that will run out of luck if you need something other than equal sized columns. If you use it for the core page layout, chances are low that you will want your sidemenu, main content and sidebar always appear in equal width columns. In Tailwind you don't, of course, but it is a wonderful feature of CSS.
Tailwind actually is future proof, but that's only because you remove Tailwind from the list of dependencies and check the generated CSS into your souce code repository. At some point all these websites will need an overhaul of the visual identity and people will realize all over again why presentational attributes were removed in HTML4 along with the introduction of CSS. You can update your Tailwind version, then, but nothing will happen. Fortunately, this "plugin system for custom code generation" can be replaced with a stylesheet.
Tailwind has certain qualities, but the things you mention are not some of them. I like that you can't simply copy the CSS from some textarea in Figma and paste it into the CSS, because that will soon make your website even more unmaintable even if it is vanilla CSS. You are in other words forced to think about the layout, the spacing system, the color variables and the breakpoint behaviors, ironically what the typical proponent of Tailwind would like to avoid. If all of these things are declared in a highly customized Tailwind preset, and if you elect to maintain complex components (eg. with synchronized breakpoint changes) in CSS files via `@apply`, it becomes an effective tool to enforce a "design system". Some might say that Tailwind's own creator advises against this strategy, but that should only encourage you, in my opinion.
Essentially, what he is saying [2] is that you should not use SQL to transform you date from one format to the other because the SQL will break when someone changes the database structure. Instead, you should just hardcode the result of this transformation directly into the database and now you won't need SQL at all. You could argue that this would be retarded since the abstraction layer enables different, future presentations of the data in question and that is exactly what I am trying to say.
My best advise is to go light on presentational attributes, which is what utility classes is, and move your Tailwind into proper CSS as soon as the implementation indicates moderate complexity [3]. Here you can make use of the `@layer components` stuff that bears an uncanny resemblance to semantic classnames, but more importantanly, now your Tailwind can easily break out into real CSS, for example to author your core page design with a Grid of uneven column sizing. Make sure to Use CSS variables for everything including your Tailwind preset so that `12px` are never mentioned in the JSON, but instead refers to `var(--base-unit-or-something)` which can be referenced equally in vanilla CSS. Keep the best of both worlds and Tailwind can add more value than it destroys.
I think you are disregarding Tailwind‘s composability almost completely and still thinking in terms of the document based HTML/CSS model.
With TW, it’s preferable to reuse whole components (JS+HTML+CSS). So in your example, you‘d have a button React/Vue/LiveView/etc component that is reused across the app. Only if _that_ is not feasible, you should fall back on @apply.
If you’re developing in an environment where HTML+JS+CSS code reuse is not possible, then I agree that OOTB TailWind is not that much better. But for a component-based architecture where you want to minimize outside dependencies, TW is IMO ideal. Meaning: React, Vue, Svelte, Elixir Phoenix (incl LiveViews) and many others.
If Tailwind relies on classnames used in the HTML and defined in CSS, then that is the document based HTML/CSS model. The composability you are talking about is a feature of CSS, not the component framework. By stopping short at "utility classes" instead of "semantic" classes that define a complex appearance, you in fact destroy composability in favor of either inheritance (assuming that your component framework allows) or simple copy-pasting. Ironically, Tailwind does feature the concept of classnames that aggregate utility classes to produce a complex appearance, it is called "@layer components", and it is infinitely more composable because you can @apply these things as well.
.my-tab { @apply my-button bg-transparent; }
There is actually a very powerful CSS framework hidden in there somewhere, but they remain intent on appealing to developers who believe that real layout is coded with JavaScript, perhaps it is because Tailwind is a multi million dollar business that relies on selling components to teams that give up on making their own.
Your components don't minimize outside dependencies when they share the same global stylesheet, by the way, they would for example not work in my website even though I am using Tailwind (if highly customized). This shared dependency, or "global variables leaking into my scope" as programmers would phrase it, is the problem that CSS frameworks have been fighting for years, and now it's become a brilliant feature of Tailwind that components can share styles. Welcome to CSS! Now you only need to define your complex layouts via @apply and you can share them as well, that is what composability is all about.
> you in fact destroy composability in favor of either inheritance
I favour composition over inheritance, so I'm ok with that.
> Your components don't minimize outside dependencies when they share the same global stylesheet, by the way, they would for example not work in my website even though I am using Tailwind (if highly customized).
I think you just made the case for using vanilla Tailwind and restraining from customizations to cater to design extravaganza. The days of pixel perfectness are over, and designers can and should IMO get used to making compromises. Form follows function, and using vanilla TW can get you more "form" in the same amount of dev time.
Having said that, wouldn't you just have to merge the two Tailwind configs and generate a new CSS file? Apart from color naming clashes (which can't be avoided in any system) I don't see any issues there.
You seem to imply learning Tailwind and CSS take the same effort, but I don't have that impression. Tailwind makes CSS tolerable for people who don't use it a lot. Its classes and defaults let me be productive very quickly.
It's not perfect and I don't like that it's yet another config file and more npm madness, but at least it's not CSS.
i know lol, the tailwind docs actually show the css equivalent side by side.
thing is, i despise writing the long ass version especially when im working with flexbox, grids, borders and everything else lengthy that i cant cram up in one liners
Only if you are coding in notepad. With any coding text editor that would be completed, with any ML model (Copilot and co.) this could take less than 5 keystrokes.
By the way, not entirely related, but when testing Copilot when it was free I noticed it was amazing at generating styles for something based on a class name. To the point I felt more productive and more in control than when using Tailwind, Bootstrap, MUI, or any other CSS "framework".
OP seems to miss the point that most everyone - or at least everyone I know - that uses Tailwind already knows CSS to a large degree. In addition, everyone I work with would rather spend time writing code than messing around with CSS and trying to name classes (great point you make, and I fully agree)
As a frontend developer I don’t understand this sentiment. I’ve learned to style websites using CSS, so has every other frontend developer, learning CSS is part of the craft, and if you skip it, you don’t know frontend development. Writing CSS is a big part of the job of a frontend developer.
Now if you are a hacker and are hacking together a website, that is fine. You don’t need to be a frontend developer to write a website, and if that is the case, use tailwind by all means. However in a team that maintains a webapp, you should expect there to be a frontend developer, and you should expect them to know and write CSS, if they are the only person on the team that knows CSS, then probably they will take some authority on that, and I would expect them to assert some authority on every code that contains some styling. If a contributor doesn’t know CSS, and writes a poor CSS code, that should be fixed during peer review. A team that is happy-go-lucky with their styles is surely not going to by writing a well crafted web-app.
What I understand about Tailwind is that it is _meant_ for those frontend developers who understand CSS, and you're essentially writing CSS when you use Tailwind - as opposed to a component library like bootstrap or material ui.
This sentence:
>Now if you are a hacker and are hacking together a website, that is fine. You don’t need to be a frontend developer to write a website, and if that is the case, use tailwind by all means.
Would make more sense IMO if you replaced the word "tailwind" with "a component library"
> Tailwind stylesheets are always going to be much smaller than normal CSS for any decently-sized app.
Instead the HTML content grows larger because of the long class= attributes. It is a bad tradeoff, because CSS gets loaded once and cached, but HTML gets loaded on every page load.
I don't understand why Tailwind proponents can't seem to see this, and tout "smaller CSS files!" as a benefit. You're still declaring the styles for every element somewhere. The client has to get those bytes somehow. That doesn't get to go away.
(And if it's just about "m-2" being shorter than "margin: 0.5rem" or whatever... I can't believe that after gzip that matters one whit.)
One of the signs of something being bloated is, when you need some compiler or "tree shaker" or <insert other fancy term here> to throw out the stuff, that you included in the first place, but are not using.
Something like "p-2 m-2 border-red" making sense relies on some imaginary grid or table layout being used. Web design should catch up at some point and get rid of that way of thinking. Websites are not bound to be aligned according to some grid. On a website things float and take as much space as needed and as available. There is no inherent need for inventing an imaginary grid. Yet so many "design systems" cling to that outdated notion. A website is not a sheet of paper in a magazine! It is like we still haven't left bootstrap behind us, or even table layout behind us, because web designers not actually knowing CSS.
Actually look at https://web.dev/state-of-css-2022/ (linked here on HN a few days/a day ago). CSS is easier to use than ever before! Now we can even specify our own specificity groups!
Once tailwind covers all needs for features of CSS, what will we have gained? We merely built another wrapper layer around the thing, that we should actually understand and learn. In my experience this will only lead to people thinking, that they should build something on top of tailwind, because they want something simpler, stacking yet another layer of abstraction, instead of actually learning CSS. At some point some sanity will return and do away with the whole stack of abstractions, because it indeed has become too bloated. (Note also, that no one will want to maintain your website based on tailwind, once the hype is gone and tailwind looks outdated.)
This kind of mentality of adding layer upon layer without watching out for the associated costs or realizing the power of already existing primitives is responsible for the tons of bloated websites we have today. For shipping megabytes of JS unnecessarily, instead of letting us enjoy the advantages of faster connections, like we should be able to.
About naming CSS classes: Surely not always a simple thing. Ideally the web design people would work together with the web development people and talk about their metaphors or abstractions on the website. Then find names for that and style accordingly. "How will we call this kind of thing here, with a picture and a label underneath and a rating? – Lets call it a product box." Or whatever else. They would build a common vocabulary and that would inform naming of CSS classes of the website. Additionally of course one would use a prefix, to avoid any name clashes with any other stylesheets.
There’s no imaginary grid here, m-2 and p-2 are just setting margins and padding. The 2 is a point in a table of sensible defaults for those values. You are free to set your own scale or just use your units of choice if you like. The defaults are well thought out though, and usually work well.
The whole point of Tailwind is that the worry about naming CSS classes goes away for most part. It turns out you can safely skip the vast majority of those granular naming decisions and conversations - that’s a massive amount of saved time and brain cycles for everyone.
If you’re using eg. BEM you have to come up with all these granular names for subcomponents that really no one cares about apart from you (the frontender I mean). If you’re not using BEM or similar and going for longer selectors in the main, then you have a coupling issue between the structure of your CSS selectors and the structure of the HTML that may make maintenance in the future harder.
It’s more like “i.e. shall we inline all our variables” / avoid naming things at all.
Adding a name for something is a weighty task that’s orthogonal to the task at hand. If you can avoid the name without losing understandability then it’s a win.
The other side of that coin is that if you add a name it has to be worth the effort.
In CSS, a number of techniques developed over the years in response to the maintainability challenges of even well thought out, traditional good practice CSS in large projects. These techniques (eg. BEM) required class names for almost every element you need to add styles to. This was to avoid long selectors that a) are hard to understand, even for experienced CSS developers and b) are tightly coupled to and generally not co-located with the HTML.
Tailwind gives us away to avoid those having to choose those names, which just took a long time and lots of conversation if you wanted to get them right.
Yes, it’s literally in the HTML so it’s coupled, but it’s co-located. The maintenance story is much simpler than with BEM and much much simpler than with trad CSS. Lower effort for a better long term result - it’s a win.
There is a downside to not naming things: All the concepts are in your heads and not in the code. It's not self-documenting at all. No one names that div or section or whatever tag via a readable class name, so any future reader will not know, that that might be a concept bound thing in the site. Styles are just applied until it works, which leads to a mess. New web dev comes in and gets told "That font is too big!". New dev opens the inspector, looks at HTML element soup. Hurries to the code, replaces some styling on that level of nesting in the HTML, but does not understand the concepts of the site at all, nor that there are probably 10 other places, that now need change.
A well thought out class name would have helped understand, that new dev is actuall editing something, that is part of a group of things, which all have something in common.
Naming things is hard, but finding good names is worth gold. Avoiding the hard parts is not going to be the solution to all problems. We would all be working in some kind of modern version of lambda calculus, if naming wasn't important. There are good reasons, why we name things. To convey meaning and convention. Not naming things hides these and makes them implicit, instead of explicit.
There is a line to be drawn somewhere. If you set your naming level too high, then it's not clear what you're doing in the details. If your naming level is too granular, then you start to lose clarity because you can't see the wood for the trees.
Regarding the problem of a developer new to the codebase being told to change the text size in a specific place; Tailwind works well in this specific situation.
At the beginning of your project, you will have chosen a (or accepted the default) text size scale. The new developer will probably choose the next largest step in the scale and step back. The new size will be in harmony with the rest of the project because it matches the scale. If this specific element is repeated elsewhere in the project, then it will be part of a component and all instances of that component will receive the change.
The right place for a considered name in this example is at the component level.
And controversial opinion - it will have just as as short a shelf-life as coffee-script. Once the CSS spec advances, there will a lot of posts with titles like: "Why you don't need tailwind" or "Learn how to get rid of the tailwind bloat", "Migrating back to Core CSS", "Back to clean, semantic HTML", etc.
The difference between Tailwind and CoffeeScript to me seems to be more in the underlying language.
JS (and programming in general) is actually quite complex, and you can't hide that complexity under a shiny veneer and hope it goes away.
CSS on the other hand is not complex at all. For that reason, it's a lot more plausible that you can make big strides by simplifying the language down to its core essence.
The occurrences have become fewer and farther between, but in such cases I'll configure my own utilities until the project catches up. The syntax for adding utilities is lightweight and embeds directly in config, ref. https://tailwindcss.com/docs/plugins#adding-utilities
This misses the point of Tailwind entirely. The point of Tailwind is to give everyone a common vernacular of CSS phrases so that I can bust out something like "p-2 m-2 border-red" super fast and still be writing code which is immediately comprehensible to everyone else on my team. There's also the benefit that I no longer have to think about class names, which is shockingly large.
Using CSS does not give you that. I don't even address the "learn to use CSS" phrase because anyone who uses Tailwind obviously knows CSS! We do the translation back and forth in our head as necessary.
It's also why I'm not concerned about Tailwind getting more features:
* Tailwind needs to have all the features of CSS, otherwise it's incomplete.
* The notion of Tailwind being "bloated" makes no sense:
* The Tailwind compiler eliminates any styles you don't need.
* Tailwind stylesheets are always going to be much smaller than normal CSS for any decently-sized app.