Tailwind CSS v3.3
tailwindcss.com
tailwindcss.com
> The problem with Tailwind for me is that Mr Wathan misrepresented « Good CSS » in his essay. His examples are BAD CSS, not good CSS. He then sets out to correct a problem with CSS that HE created by writing dirt poor CSS. `.author-bio > div > h2 { color: red } is NOT good CSS. The div part has no reason being there (why would the div change the color of the title ?). After presenting this auto-created problem, he sets out to solve it with BEM, where you need untold numbers of classes for everything. So now, CSS has a naming problem, created to solve a non-existing auto-created CSS problem. And Tailwind now solves this pseudo-problem.
Apart from this, the thing that really bugs me is that every advantage claimed (apart from one) is also non-existing because if you do your CSS right, the same claimed advantages arise in pure CSS. Design tokens ? No need for json, custom properties are all you need. Specificity ? Cascade layers, pseudo-selectors are here for you.
The only "advantage" I see is the possibility of working in one file only rather than a couple of files. And that, for me at least, is not a real advantage but only a justification for being lazy. There's no way the price of all these processes and dependencies complexity are worth the laziness-added value.
Does someone care to "prove" me wrong here ? At least, can someone engage these arguments ?
Looking forward to it!
Add to it that for some weird reason web’s style includes layouting, which imo should be a separate thing entirely, and this is the primary reason why any given CSS has to be specifically created for a given HTML template, and why seemingly benign CSS modifications can move that 3rd step of the checkout page, rendering it completely broken.
Restricting CSS to a subset of only cascading some very basic properties (fonts, colors, default font-size), and letting everything else be managed on a per component basis (where close coupling of style and template absolutely makes sense) and simply layouting those components to form the given design makes much more sense to me (and frankly, it was sort of figured out a few decades ago by several desktop GUI framework..). And while you can write vanilla CSS this way, tailwind just restricts you to this subset — the same way there sure exists some safe subset of C, but you need something like Rust to restrict you to that [1]
[1] I know, this is not really how it works, it’s only for the analogy’s sake
Otherwise, you have to take great pains to ensure styles don't conflict or accidentally apply to things they're not intended for. Or you have to use some other framework/tooling to convert your css selectors and markup so that scoping is enforced
A blend of shadow and light DOM in web components solves most of the issues I've run into over the years.
It's also easy to scope styles to a custom component in the light dom with:
my-component .header {...}
I do this a lot in light DOM web components and render the styles with lit-html as part of a template.My general approach is to keep most application level components in the light dom for styling, and only use shadow dom for library-like components, mostly layouts for slotting light dom stuff.
I never have to worry about clashes or getting too cute with my naming conventions. You can just use a h1 selector and not think about it.
And here's an experiment I'm working on, where all styles are scoped to components because all static DOM trees become custom elements with their own shadow root: https://github.com/aalin/rdom
FWIW if you are interested in Web Components I would say Lit is hands down the best entry point I’ve come across. Strong recommendation and nullifies most of the common complaints you tend to hear associated with them.
Simple linting rules can get you lots of mileage here. First and foremost, you ensure that in any component CSS file, ALL selectors begin with a class that mirrors the filename.
It seems to me that this can prevent the vast majority of conflit or spillover occurences. Don't you think?
Legitimately curious here as well!
But then you're adding a convention that isn't as easy to follow. Maybe you follow it, but what about new people. What about people who make a typo? Are you going to make a VS code plugin that points out if someone mistypes the file-based class in the CSS file?
What if the file is renamed, or moved? Do you then have to go update every selector in the CSS file?
This all seems so much more brittle to me than just using tailwind, and the VS code plugin show you the possible class names you can select from when you start to type something, as well as rules for each of those class names. It also catches (and highlights) contradictory rules, when applied to the same element. You can't do that from the CSS (there's no telling what the declaration will be used for, from the css in isolation), and unless you make your own editor integration, this won't happen when editing markup either.
If the file is renamed, then yes, you change the selectors. That's a simple operation. But I think the same goes for any JS framework where you'd create components. If you change "button" for "secondary-button" you'd have to change it in at least a couple of places I guess? Either way, you should limit these kind of operations to a minimum.
And what if I don't want to use VSCode? Maybe there are Tailwind plugins for every text editor...
But more importantly, that's quite easy to include your CSS files in the autocompletion of, for example, Sublime Text. I'd guess it's the same in VSCode. And again, simple linting should prevent much of these problems I think. You can easily lint contradictory rules in a ruleset. Stylelint would be perfect for that.
And if by mistake you have contradicting rules across rulesets, then a quick look at the devtools will tell you where the problem comes from. On a sidenote, the devtools become real difficult to use in a Tailwind-like paradigm.
I'm not sure I understand this argument. If I rename a component and the file it's in, I get automatic import renames across the codebase without having to do anything myself. And if I didn't, I'd get errors trying to run the code (I'm not sure how you'd configure CSS to do the same thing with unmatched selectors, though I guess you probably could remove them from the output at least with postcss)
> And what if I don't want to use VSCode? Maybe there are Tailwind plugins for every text editor...
You do you, but according to the 2020 state of JS, 86% of JS devs were using VS Code, and 20% vim (which also has tailwind support): https://2020.stateofjs.com/en-US/other-tools/#text_editors
They removed the question so I don't know what current trends are, but Tailwind is at least supporting 90% of possible users with just those 2 (and I haven't looked into support for other IDEs)
> On a sidenote, the devtools become real difficult to use in a Tailwind-like paradigm.
I haven't found this to be the case at all, I'm not sure why Tailwind would make the devtools more difficult. If anything, it makes it easier since I typically only have to look at the CSS section for elements which have inherited styles
As for support in text editors, you can still autocomplete any class you have in your CSS. And the CSS linting will give errors too if you have problems. And there are CLI programs for discovering unmatched CSS, which works pretty well in my experience.
And the devtools suffer from all the added classes. It can slow down to a crawl depending on your machine. And you can't play as easily with the styles... If I disable a property in the cascade, all other items with this property will lose it. I would say it goes against the devtools grain. But I guess it depends on your usage.
But, other people do things differently so maybe it's not the best approach for them; but for my limited needs and experience, it's been fine, if not great.
Because, as I said elsewhere in the thread, I think (maybe wrongly) that simple linting could rid you of the vast majority of these problems.
But, please, if you mean something else, do comment! I very much like this discussion.
When I try to "separate" CSS, I always end up creating utility classes (so kind of like Tailwind).
Currently, I like to use a combination of utility classes (e.g. class="text-bold") and high-level class modifiers (like a ".pricing" wrapper, and then I can modify everything inside the pricing section like spacing, font sizes, colors).
.pricing h2 { color: var(--color-tertiary); }
I think this makes more sense than adding "color-tertiary" class to each h2, because if I want to change the color, I would have to modify it in all the h2 tags.I would use "text-bold" if there is a one-time instance where I want the text to be emphasized. If there can be a rule extracted (e.g. make every first word bold), I would use CSS selectors/classes to modify all those instances.
Writing good CSS for interfaces in a web application of significant complexity is expensive and time consuming. Tailwind solves that problem very well. Other CSS frameworks have done so as well over the years -- I wouldn't call Tailwind unique -- but the micro-class approach it takes is perfect for modern interface templating systems like Vue, where you tend to abstract at the component level instead of at the style level.
I see that bad developers could make mistakes, but besides that, which is kind of easy to lint, the only advantage I see is the need to maintain only one file instead of two.
What do I get wrong?
edit: syntax
If I need to add some padding, I slap on some p-4, my browser refreshes, and I see the result.
I don't really get the spiritual debate. It's a tool, use it or don't.
And for me, at least, this is not a spiritual debate. On the contrary, this is a very practical debate. The popularity of the tool and the signal it conveys absolutely has consequences on all of the development community. Whether I like Tailwind or not, I have to maintain projects that were done with it, I get asked about it, etc.
I think that saying "it's just a tool" is kind of short-sighted. It's a paradigm. And as such, its practical implications are far reaching.
I'm stuck on some rather legacy (read: fashionable 5 years ago) stack either way, but its interesting that I'm conducting an interview later today where the applicant ensured to exhibit a Next/Tailwind/TS app that runs on Vercel.
I can't blame them either, I remember interviewing two summers ago and being asked if I had experience with Next straight out the gate despite it not being mentioned anywhere in the job description.
The "traditional" approach to authoring HTML and CSS is predicated upon on idea of separating concerns. The idea is that your HTML should not depend on your CSS, and your CSS should not depend on your HTML.
The "utility-first" approach reacts by claiming this is wrong. It goes on to reason that either HTML depends on CSS or CSS depends on HTML, but neither are independent. This is what Adam Wathan calls "dependency direction."[0]
0. https://adamwathan.me/css-utility-classes-and-separation-of-...
> if you do your CSS right
I think the reality is, when you hit a certain size and scale of developers working on your product, it's next to impossible to do CSS "right". It's just not a skill that's widely shared in large frontend teams - a part of this is that the role of a "frontend developer" is pretty broad now. There's a lot of frontend work where you just don't end up styling things.
This is why you might want to abstract out HTML is styled one level up, and then go from there. Having a good framework for people to style things consistently, and then create higher and higher level components for all the common patterns.
Personally, I think the better solution for this (as opposed to tailwind, not "let everyone write their own bare css") is something like Vanilla Extract's Sprinkles to create your meta framework for styling with full type safety and editor suggestions https://vanilla-extract.style/documentation/packages/sprinkl...
I think it's useful to think about analogies for other parts of the tech stack. You probably don't want every backend developer writing SQL by hand every time you interact with the database, so you create various levels of abstraction on top of that to "limit the damage done by careless SQL developers".
The negative sentiment ("careless CSS developers") isn't necessary. It's not about fixing the problems from bad developers doing bad things, but just giving people better alternatives to make it not possible for anyone to do "bad" things.
I get what you're saying. But again, linting should be enough to guide you in writing good CSS. It's really not that hard if we are interested. No need for a whole new way to do it. What I generally get from discussing about it here or elsewhere is that lots of devs just don't like CSS. Which is a shame since it's central to our work as Web devs. What do you, yourself, think about this?
the problems these things all try to solve are not so much how to style things, but how not to have the cascade bite you because your devs didn't understand that part.
So how to describe that a problem - is it a CSS data model problem?
But because some people don't know how stuff works you come up with rules that if they follow they won't mess stuff up. They won't make things in the best way, but they won't screw stuff up either. hurray!
I think simple linting could be part of the solution.
However this is not the cheapest (because costing learning time) or simplest way.
I installed a vscode extension and just hit CTRL+SPACE to see what my options are.
I guess if people only wrote really good CSS in the wild, or hey even agreed upon what it looks like, there would be no need for tailwind, that's true. But that's not reality.
But could we not care and try to use this native language as it was designed instead of short-circuiting it by slapping costly dependencies on top of it? Wouldn't it be a better approach considering, among other things, the coming ressource optimization in HTTP3?
However, I find the responsiveness side of things very useful.
> I'm just writing the css but in a different way. cursor-pointer class for "cursor: pointer" for example.
The difference is, when writing the CSS yourself you also have to find a way to apply this to the thing you want it to apply to. Which means you have to write your own selector. Which gives you 1000 guns pointed at your feet, and maybe two aimed away from you (and one of those is just the same one that tailwind gives you, but less portable).
For me, a framework should deal with the basics and make thing easier. Making it so you just write css differently seems odd for a framework. It seems more like a css parsing framework than anything. The tailwind UI seems like a framework that provides you the basics.
Or maybe you don't like CSS at all?
I also leaned in heavily to the component model with Web Components which was another huge win for my experience with CSS.
I actively enjoy it now rather than dread it. Catching up wasn’t too difficult and if someone else is in the same boat I would recommend the investment.
I completely disagree with your opinion, as well as numerous other Tailwind developers lol.
Your opinion of Tailwind is kind of the like what the person who may have believed the flat head screw was the way when they introduced the Phillips head screw. Both types of screws are great tools, but a Phillips head may have seemed less superior to you because you didn’t understand its purpose and value.
As for your analogy, I'm not convinced it's adequate. The Phillips screwdriver does not reinvent the way to turn screws as Tailwind does here with styles. The Phillips screwdriver does not add complexity in the building of houses.
Regarding design tokens, they are taking notes from 1996, and they realized that it is much more computational efficient to describe your component visually with inline styles compared to loading separate style sheets.
Tailwind and CSS design tokens in general make it easier to make smart, efficient choices from curated palettes. Design tokens also create a common language for everyone who uses Tailwind - both across teams and across projects, which can break down communication barriers in large scale projects.
And I'd say that striping the cascade, removing selection and specificity and implementing new ways to do the same things (ie: peer-[:nth-of-type(3)_&]:block) is indeed reinventing our use of CSS.
Tailwind is just that, but unified across all projects, with better tooling (VS code integration, tree shaking, lighter css files)
I’ve been working towards emailing you to ask if I could upgrade patrickcollison.com
There are hundreds of little tiny css style rules and fixes for a perfect website, and you have to remember them all. Tailwind has done all of that, plus a bunch of more.
Their utility classes are their biggest feature in my opinion. Just the ability to set dark mode styles inline with my light mode styles seal the deal for me alone.
So I have all the same kind of files, and change the design tokens accordingly. The only difference is I configure in CSS whereas you configure in JS. You can bundle it all and keep reusing the same files as you would do in Tailwind.
For someone starting a brand new app from scratch, they might want to lean on existing css design token libraries.
Design tokens aren’t anything new; Bootstrap has been using them for margin for years. mr-1 mt-2
To do CSS properly, you need to name classes, you need to come up with CSS cascades that work.
Being programmers we would love to categorize and name things all day long. Ever heard how we over-engineer things because of the DRY principle?
But we would love to name classes and do CSS properly only theoretically. In practice, we run out of time making CSS with nothing to show a week into the task except a CSS kitchen sink demo. By the time we're done, the scope of some component has grown in a way we did not expect and is hard to represent without markup change.
Tailwind on the other hand removes the task of thinking how to name the thing we're making. A appbutton appbutton--state-user-notallowed or a touchbutton touchbutton--disabled? In Tailwind it's just a a blue-600 rounded rectangle. Scope changed? No problem, now it's a green-400 shadow special rectangle, without checking where else it was or will be used or coming up with a new name for this special rectangle.
It's just faster. Not strictly better.
You don't have to name classes for everything inside a component. You only have to name the component, as in Tailwind. Afterwards, tag selection is totally fine. And with all the new CSS pseudo-selectors it is now easier than ever to be styling with low specifity while including markup options.
Have you actually used Tailwind for a week or more?
But Tailwind is sensitive to DOM changes too, since every style is on tag. You wouldn't remove any tag without understanding its usage in a component using Tailwind. Why would you treat a CSS component any other way? If a tag's there, it must be used for something. Again, I may miss something but I see that as normal care and dilligence in both ways.
On a sidenote it's now easy to include, for example, all headings to be styled the same in a component, thereby limiting the need to adjust the CSS in case of a change of tag. There are many ways now to leave markup options opened if need be.
CSS is a generalization programming language, with specificity meant to be used for _exceptions_. Therefore, CSS should be used with general statements first, contextual statements next, utilitarian statements following, and then and only then exception-specific declaration in the edge cases they are needed.
Programming with CSS the way it was intended: Cascade, Inheritance, and then specificity, generally produces a quite DRY experience.
The one thing engineers/other programmers seem to have missed, continue to miss and seem intent on missing into the future is this: CSS is a static programming language that must account for being in and rendering dynamic contexts.
When I'm in JavaScript, I _depend_ on having the one thing, be the one thing, whenever I reach for it. I depend on immutability to keep my life sane.
When I'm in CSS, I _must_ account for flexibility, because I cannot predict the future, and I cannot predict all the various contexts in which my declaration might exist. Therefore, each CSS statement I create is based on how I would _like_ my thing to behave based upon a variety of circumstances, and to have static fallbacks when all else fails. My sanity is in producing the most responsive yet stable experience for the unknown.
Tersely, but without apology: Tailwind is for developers who do not want to take the time to learn CSS the same way they took time to learn JavaScript [or insert language of choice].
And while using Tailwind, I still have to know where I include my components. I still need to test different instances in different places.
With that in mind, I don't see the added benefit of Tailwind here (again, other than limiting the damage done by careless devs). Maybe I'm missing something?
Adopting Tailwind is easier than thinking about CSS, even if they end result is (IME) just as wonky and disjointed as a ‘bad css’ implementation
Unfortunately, I haven’t experienced this :/ (yet)
CSS is the low level language of styling. For the same reason I use C# or Javascript instead of assembly language or C, I need to get shit done.
The advantage of Tailwind is commoditizing CSS into something no one has to really think about as deeply as you're suggesting we do. Someone who cares to can do that thinking and put it into a Tailwind class in one of the versions. It's also portable, in that anyone who works with Tailwind can come in and immediately contribute, instead of figuring out whatever structure we've built ourselves.
Tailwind provides me a lot of value in that it lets me continue building while providing a very nice UI (which is required in modern times) and not having to engage too deeply with styles, because I'm not trying to be a master of CSS, I'm trying to build a wholistic product and I have 500 other things I need to do.
* I'm a backend guy but recognize I need nice UIs.
Because, you can ship the same experience with less code, less dependencies, less complexity. You can better serve users by easily catering to their preferences via the cascade. You can make use of new technologies that increase performance (see, among others, HTTP3). You can profit from the newest supported CSS properties that are way more expressive and give you more flexibility for cheaper.
It's about trying to do the right thing.
Edit: I guess this question kinda doesn't make sense. There's a lot of CSS syntax that isn't available inline in the style attribute and the example I gave can be done with "traditional" CSS classes. The thing I'm really considering is how one can semantically choose HTML elements while using small bits of inline "styling" (read: atomic CSS classes masquerading as styles) to change the properties which need changing and forego CSS otherwise.
Anyway, ultimately I don't think that's necessarily better than other styling implementations.
I have learned CSS and absolutely love the cascade. If I hadn't, and was on the clock, I'd consider something more shortcut-like, even if it's less precise.
If I was using React, writing components in the way SPAs require, Tailwind could make more sense. SPAs fragment code into such little pieces, that thinking about CSS as a whole becomes less necessary.
But, I do know CSS, I have adopted the ITCSS code structure, I do have the Tailwind colors in my SCSS codebase, use the Utopia fluid typography and spacing scales, and with grid, container queries, flexbox, gap etc. life is good. CSS is fun.
But, is it a "good" argument though?
So I guess I'm a Tailwind convert :) It's very quick and easy to get stuff done using it--the design system is very well thought out. For internal dashboards I think you're still better off using an off the shelf component library like MUI, but Tailwind is a really good option for anything else imo.
[1] https://sophiabits.com/blog/css-in-js-to-tailwind-better-web...
> about a month and a half ago
> unmaintainable soup were unfounded
I see this a lot, but rarely with a qualification. How did it quell your fears about unmaintainability? What about tailwind makes it maintainable?
- styling is scoped to your components. You won't break your UI trying to refactor rules & selectors
- by default you don't need to invent class names. The components provide enough context
- it forces you to make a selection of colors an spacing, leading to a more coherent style.
- it is easier to understand than a lot of other css frameworks. It is just a "basic" rule generator with some QoL like automatically pruning the rules you are not using in the production code.
Tailwind is similar: instead of extracting styles out to a separated styled component or even a separate .scss file, you collocate them with the rest of your layout. When I read code using Tailwind it's easy for me to "see" how things will look in a similar way that I can "see" how a React component will function at run time.
More concretely, I think these three things were important for me:
1. There's a really solid design system underpinning the Tailwind utility classes. With styled-components you start from nothing, and with off-the-shelf component libraries (e.g. MUI) you get a design system that isn't quite as well thought out. Tailwind's classes just work together really well out of the box because the defaults are so sensible. I'm not a designer, so this is a really big win for me.
2. Components help prevent class soup. I suspect I wouldn't enjoy Tailwind quite so much if I were writing plain HTML, but for things which _do_ need to be reusable like button styles I'm still writing code that looks like `<Button>...</Button>`. Nothing really changes here from styled-components -> Tailwind other than how the styles are written; they're equally maintainable.
3. One-off snowflake UIs are really easy to implement, because you can just write your classes right then and there. I've never worked on a nontrivial web application where _everything_ fits cleanly into the design system, and going through the ceremony of creating a styled component just to add a little bit of additional spacing is a pain. It also sucks for maintainability because a name like "Spacer" doesn't tell me anything about the styles, so I need to context switch and jump to the definition. In contrast, seeing "mx-2" instantly tells me what's happening.
I do think Tailwind's something that benefits from first-hand experience, though.
edit: syntax
1. It increases mental overhead. It is not possible to tell whether a component contains pure CSS styles or adds some functionality, unless you open it and read its code (in that point, it has lost all of its benefit for me). With CSS classes or even HTML style attribute, this distinction is immediately obvious: style vs. function.
2. It clutters the codebase. You'd find all sort of little components sprinkled everywhere.
Both of the above critics could be addressed by implementing a convention, however. For example limiting the use of styled-components to a specific package. The second issue is mostly programmers' fault, not styled-components. However, with CSS I don't have any of these problems to begin with.
https://tailwindcss.com/blog/automatic-class-sorting-with-pr...
Now fingers crossed that at some point we see a 25. XD
Edit: seconding sentiment of thanking the tailwind team <3
Vanilla CSS, SCSS, BEM, Bootstrap, Styled Components, different kinds of CSS in JS solutions and I still prefer Tailwind over the other methodologies and libraries because I don't have to think about abstractions and naming things. Abstractions are huge foot gun in frontend development because it kills all flexibility. With Styled Components or similar libraries you have to wrap all your components with all kinds of variants that inherit properties. Composition over inheritance is a huge benefit of Tailwind. The big problem with CSS is the specificity and if you ever worked on a real big project with BEM or vanilla CSS/SASS it will eventually become a huge mess of specificity and more and more specific nesting of class selectors to override other styles that you don't want. With Tailwind you can just add exactly what you want, nothing more, nothing less.
Sure the html is "ugly" but that part is invisible.
It is also very likely your bundle size will be smaller because it only adds the CSS for the helpers that you really used.
Just my 2 cents I guess. People should use what they like.
However, one thing I'm still wondering about is how easy it would be to maintain visual consistency in a large project with lots of components, and lots of different developers working on different parts of the app.
Say the branding guidelines a certain style, like rounded corners with some shadowing and a hover styles, something that can't be done with a simple utility class. This should be consistent across many different components and pages. Then, someone in design updates the guidelines to have a different value for rounding and shadows.
With Tailwind out of the box, each component now has to be updated separately, and developers have to remember, or at least be able to check in documentation if that exists, which components use this particular style.
Is the answer then simply to use @apply for combinations of style? Doesn't this simply re-invent CSS classes, and create another layer of abstraction (you now have a class, which is composed of other classes, which themselves are composed of values set in custom properties).
I'd be very interested to hear how people manage this in large teams, over time.
Then on top of this we have components library with common basic components and layouts
Then inside the apps we use the components and that Tailwind config and it works quite nice.
We have rules for tokenized colors and sizes so it all references the config.
There are problems and all, but all in all I think is quite good
Use tailwind as a tool, have a component library that can be put together in a couple days max, and now you have ubiquitous styling language and don’t need to waste hours on css of all things.
There are bigger fish to fry.
How is that better, than just writing custom CSS classes for components + having some util CSS classes?
It's definitely worth building a few small projects - it looks and feels bad at first, but once you get used to using it, it's really hard to go back to anything else.
I think the ability to mix up things like that is what makes it quite powerful. You don't have to go digging through your sources to find all instances of '.my-one-off-class-that-some-random-dev-also-used'.
Tailwind together with view components has changed how I structure my code and it creates quite a bit less work than my company's old more BEM centric approach where we would create lots of tightly coupled CSS code controlled by variables and such. I find it easier to grok as well, because I don't need to reference SCSS files to determine the implications of applied classes when debugging or similar.
Now most of the component requirements can be codified in a few classes in our view component instead. Does it look kinda ugly, yeah sure. But I'm sure it has saved quite a few hours for me since I switched over.
This might just be because old process was even worse, regardless it has been a very positive change for me personally.
However, I use it in my day job, and here it is useful to us as a team. The variables combined with the tooling ensures we write consistent styles across our site. The color names and text sizes also correspond to what our design team uses in Figma, making implementing and updating designs quick.
That said, I still find it a pain to read, and we could probably have set up something very similar with CSS Custom Properties.
You could import your favourite design framework (say, bootstrap) as SCSS, change its variables to suit your design, and create any custom components using @extend:
.custom-component {
@extend .some-bootstrap-class
}
Also nothing prevents you from creating mixins, functions, etc.Just keep it first-order, as SCSS functions cannot return new functions.
1) it is more standardised (since it is written in html rather than custom classes) which means you can pretty much copy a component from one project to another without worrying that maybe the css naming overlaps etc. It just works.
2) it limits the decisions you need to make. No need to decide exactly how many pixels the padding should be. Just pick p-4. And if that is too much take p-3.
3) You dont need to worry that something in a totally different part of the app will break if you change the css to change the styling of a component
4) It is just faster to write and in my opinion easier to reason about (im sure this is personal) since I can see directly in the html what styling is applied and i dont need to go and dig in different stylesheets to find out what "custom-button-large" does
Not bashing Tailwind. It’s amazing. But I found myself making thatsamefuckingwebsite.com again and god damn if I didn’t want something to look different.
And as soon as you’re writing your own CSS, you might as well just write your own CSS.
Like literally the first time you write your own particularly uniquely styled component and have to mash your own classes in with Tailwind’s you think, hang on, why don’t I just…
Edit: like this site. Just found it via elsewhere. https://www.usebubbles.com/ First thought: justanotherfuckingtailwindwebsite.com
One of the big reason to not do that in the past was in order to disconnect the presentation from the page structure, but if you have individual classes for each individual css property, you're back at tying the two together.
What am I misunderstanding here?
Re: separating presentation from page structure, Tailwind is designed around the opinion that that whole idea was mostly wrong, similar to how frameworks like React brought back the `onClick=` attribute when everyone was saying “unobtrusive JavaScript” was the best practice
Wrote about this in depth a few years ago shortly before releasing Tailwind, can read here:
https://adamwathan.me/css-utility-classes-and-separation-of-...
2. grouping css classes is also hard
3. having some unified naming for all utilities for all developers in your team is much easier to understand and maintain?
4. you reduce 3 steps from creating css file -> writing css class -> re-write them back in the html, vs writing classnames
5. you can have unified styling with color, spacing etc instead of rogue assignment
I'm a tailwind convert from bootstrap but it's definitely worth it after trying. Have created 15+ project with tailwind ever since
But the advantages out-weigh the disadvantages, IMO:
- provides a simpler, thoughtful, more logically organized version of CSS (with nice ways to extend it and escape hatches if you need them). - the “CSS” —- meaning the CSS-like classes — live right on the HTML elements they style.
It makes it feasible to directly style HTML using CSS-like classes, rather than having to build and, importantly, maintain separate CSS and your own abstractions mapping classes and element types to styles.
You don't have to remember whether you had a 4px or 0.5rem or 4% border radius on your buttons, you just have to remember sm, base, lg, xl, or full. You don't have to remember the scaling of your fonts, you just use the same nomenclature.
This:
1. Creates a more cohesive codebase where most everything is using the same units (I've never worked on a project where there wasn't a rampant intermixed use of em, rems, px, and vw/vh -- except on tailwind projects)
2. Creates a more structured component feeling -- you don't ever run into the cases where border radius is off by 1 pixel or widths are using different units
3. Creates a more cohesive design feeling -- text sizes are balanced with eachother, widths are balanced nicely, colors grade smoothly, etc
I was a long holdout on tailwind. I always say it as just another way to write css except on one line (css golfing). Either I was ignorant in the beginning, or it changed along the way, but by the time I started using it around v3 I couldn't believe I was holding onto CSS for so long.
It pretty much always were?
> How is that better, than just writing custom CSS classes for components + having some util CSS classes?
1) colocation of style and layout in the code (no separate file, no "dead-code" CSS classes) 2) isolation of styling rules (this style applies ONLY to this HTML component) 3) Built-in standardization across the codebase (spacing, colors, etc)
Only works well in component-based web development (ie React, Svelte, Vue, etc) as opposed to inheritance-based styling (old school CSS+HTML)
You can get a lot of the benefits of tailwind using other tools like CSS modules (isolation) or colocation (styled-components), or with plain CSS features (CSS variables for standardization). But tailwind has a major benefit of introducing almost-zero runtime impact (vs styled-components) and having everything already built-in (vs css-modules. There is very little the user of the lib needs to think about architecture-wise when using tailwind
Funny how that's not how it's advertised on the landing page. The first animation of its use is just basically plaintext HTML document.
I can't imagine using it for that.
That may sound absurd given tailwind classes represent single CSS property value assertions. But you can pretend and say "look we're using a preprocessor and pipeline step for our CSS" all the while you're hand-crafting your CSS like in days past, making tailwind act like a no-op submarine, and without the bad looks of inline styles.
The benefit is that you don't have to create a badass taxonomy for your frontend classes (that might or might not evolve well) just because CSS is there, especially if you're using CSS-in-JS anyway and might prefer relying on code organization via JS (that you're using anyway).
CSS rules are just a redundant syntax for markup attributes anyway.
Tailwind is just a CSS design token and utility class library at its core. It’s the Bootstrap of the 2020’s.
Regarding design tokens, they are taking notes from 1996, and they realized that it is much more computational efficient to describe your component visually with inline styles compared to loading separate style sheets.
Tailwind and CSS design tokens in general make it easier to make smart, efficient choices from curated palettes. Design tokens also create a common language for everyone who uses Tailwind - both across teams and across projects, which can break down communication barriers in large scale projects.
Because the classes are shared to begin, there is less redundancy in the final CSS than using custom classes, perhaps with mixins to do standard flex or positioning patterns. So the resulting CSS file is typically relatively small and kept small by the dead code elimination. You can ship the entire CSS file to any page or on the initial page load for a SPA and not worry about code splitting your CSS, which can be troublesome in some builds.
For example, if you define class `.myclass { @apply bg-red-100 hover:bg-red-50 active:bg-red-200 p-2 md:p-3 xl:p-4 animate-pulse; }`, tailwind will generate quite a big css ruleset, with @keyframes and @media-rules. And all of these media-rules are extensible, so if you want a different size for "md" or new suffix, just define it once in config and use everywhere.
- It's a DSL within a DSL, which as a rule of thumb I always avoid because it means circumventing any static analysis within the main language. The rest of my complaints are mostly derived from this fundamental issue.
- It reminds me (not in a good way) of bootstrap classes circa 2011
- Unlike styled components, there is no static typing or intellisense as it circumvents the TS compiler. I'm sure Tailwind has its own solutions to this problem, but I have enough tooling to deal with already
- It's an arcane "language" that needs to be learned in addition to every other language in your codebase, which makes it difficult to onboard new devs
- A string value containing a long list of short identifiers does not make for readable nor maintainable code
- In 2033, CSS will still be around. Nobody knows whether Tailwind will be, but if "reminds me of bootstrap" is any indication, the ecosystem will not be thriving.
- It's not easy to remove from your project if you decide you don't want to use it anymore (unlike solutions that use CSS or object syles, which can be more readily swapped between frameworks, e.g. migrating from MUI to Emotion or from Emotion to CSS modules)
- None of the problems it purports to solve are recognizable to me
I know that people like Tailwind, but frankly I don't see why, and I suspect there may be some element of stockholm syndrome driving its popularity. And I'm always skeptical of any technology with culty vibes around it.
As for me, my preferred solution is either CSS modules or emotion.js, using either CSS or styled objects, both of which are fully supported by intellisense and typechecking, and are based on a 25 year old standard language instead of a 3 year old DSL within that language.
Creating a "well defined color palette" is usually a part of the design-process when creating a new application/website. I understand that some people prefer the Bootstrap-process of already having a bunch of colors defined for you up front, but it certainly doesn't suit every project.
Plus personally, I don't miss the times when Bootstrap was trendy and every website basically looked the same. I like the individuality of the framework-less web.
You can easily do this in tailwind.
At the very least it should save a step or two compared to building the design system out yourself in a new project
Unlike Bootstrap Tailwind doesn't have hardcoded components and full on UI elements like "breadcrumb-item" or "modal-title". You want components? You build them yourself.
Tailwind is literally just utility classes with a few defaults for sizes and colors thrown in.
> unlike solutions that use CSS or object syles, which can be more readily swapped between frameworks, e.g. migrating from MUI to Emotion
You're confusing a CSS framework that actually is like Bootstrap (MUI) with a way of writing CSS (emotion).
You'll have significantly more troubles trying to move away from MUI with its rigid requirements for code structure and CSS (Typography variant="subtitle1" and Button variant="outlined" etc.) than moving away from Tailwind which is really just a collection of CSS classes that you may or may not use as you wish.
And to be clear, I despise MUI, and actually did migrate from it to Emotion, which was relatively easy because it uses Emotion under the hood. But what I'm getting at with the example of Emotion to CSS Modules, is that they both use standard CSS and the differences are mostly around where it's defined and how it's loaded. Migrating wouldn't be a piece of cake, but it would be mostly a matter of moving blocks of code around, and could be largely automated. Whereas with Tailwind, the utility classes are only meaningful as long as you're fully plugged into the Tailwind ecosystem. There is no "eject" button, AFAIU.
And has nothing to do with Tailwind, Bootstrap, or MUI
> But what I'm getting at with the example of Emotion to CSS Modules, is that they both use standard CSS
So does Tailwind
> Whereas with Tailwind, the utility classes are only meaningful as long as you're fully plugged into the Tailwind ecosystem.
Same with MUI. Again, it's much harder to migrate off MUI because it literally binds you to a very specific way to structure your components and other components inside those components.
Hell, you can't even move from MUI version X to MUI version X+1 without half of your site breaking.
You want to move away from Tailwind to something else? Bring in that something else and use it alongside while you replace your components written with Tailwind classes with that something else. Because Tailwind is literally just CSS.
I do not like it in a boat, I do not like it with my coat, I do not like green eggs and ham.
The central argument of its value seems to be "you need to try it to understand it," and I just don't find that to be a compelling argument. It doesn't claim to solve any problems that I recognize in my current workflow of writing well-scoped styled components.
I remember the arguments in 2008 from people who insisted they needed a physical phone keyboard, like a blackberry. They need to actually try a good touchscreen, vs provide untested arguments why physical keys are better. (Better in some ways? Sure. Overall? No.)
At some point it becomes an ego thing, people don’t want to admit their initial impressions were shortsighted. And it’s ok. The better experience wins out.
You're right I should try it, and maybe I will try it on some throwaway project eventually, but it's not a priority and I have no interest in adding it to ongoing production projects.
I was very open about the fact I haven't tried it from my first sentence, which was "here are the reasons I have no interest in trying tailwind."
I would have more interest if someone could explain a compelling problem that I recognize and that Tailwind solves. But nobody can do that, it's all just "you have to try it [and learn our initiation rituals] and then you'll understand!"
There are countless blog posts and threads listing the advantages, but it’s better to spend that time using it and you won’t have to take someone’s word for it!
From the creator of styled components himself: https://mxstbr.com/thoughts/tailwind/
So, how's this: I promise I'll try the playground for 30 minutes sometime soon. :)
But I don't believe that's enough to learn it, because you'll still need to be constantly referencing the documentation to remember all the weird little utility classes. That's why I didn't like Bootstrap - it required memorizing some esoteric language that is totally useless ten years later. Whereas the CSS I learned in 2004 is still (mostly) just as useful today as it was then.
The reason I'm conservative in the technologies I adopt is because I've been doing web development for nearly 20 years now, and I've seen five or six cycles of fads begin and end. Very few technologies stand the test of time, and it sucks if you end up stuck with one of them on the tail end (heh) of its hype cycle. Or sometimes it's not even the end of the hype cycle, but just a major upgrade to a new version that requires you to change hundreds of files in your codebase (this is the main reason for my dislike of MUI). I don't know if Tailwind has that issue with upgrades, but I know CSS certainly does not.
Tailwind is not that. Tailwind might disappear over time, but only because future improvements to CSS might borrow ideas from Tailwind
I’m similar, webdev since the pre-jQuery days, and hate framework churn. Tailwind is kind of like jQuery in that it gives a consistency layer that CSS was missing (just like jQuery gave a better way to interact with the DOM).
Either way you find it, glad you’ll be giving it a shot!
You honestly have no idea what you're talking about, and you're making that very clear.
Lots of people in this thread have used tailwind as well as many other CSS maintenance strategies, and almost all of us prefer tailwind.
Not that mass approval makes it "right", but you certainly can spend 3 days writing your next greenfield project with tailwind, and then if you want to "eject", it would take all of 20 minutes
Rudeness aside, I made it very clear from the beginning that I haven't tried Tailwind, and my criticisms were based on fundamental principles that could apply to any new tech.
Of course I don't know what I'm talking about when it comes to tailwind - I've never tried it. I hoped my points could be read as constructive criticism as to how to convince someone to try it, rather than an invitation for the cult-of-tailwind to pile on with insults and appeals to authority of influencers pushing foot-in-the-door sales tactics. It doesn't exactly instill a lot of motivation to join the ecosystem, and it only proves my point about the culty vibes around it.
> There is no "eject" button, AFAIU
AFAIU as in, as far as I _understand_.
So tell me, what's the process for ejecting?
Also, using tailwind doesn't mean you can't use CSS the way you're used to in addition to the tailwind classes, though it's possible you could end up with specificity issues if, for example, you've added a tag selector, like `div {...}` which is overridden by a class you've added to a specific div in your markup. This is pretty straightforward though, and if you've been using CSS for any amount of time you'll still find you have to think a lot less about specificity than going all-in on your own CSS
You ship less CSS, especially the more complex your app gets. A app built with custom classes ends up growing linearly, often with lots of repeated css code. With Tailwind, the amount of css added always ends up being logarithmic.
It also ensures consistency across the codebase in both naming conventions and styling (e.g consistent spacing ratios) without seniors having to be vigilant about policing PRs.
Finally, the majority of people who have tried it find it quicker and easier to code with. Which means you can ship more functionality in the same amount of time whilst maintaining the same or better styling standards.
So there are three of the engineering benefits to using it. If you don’t like it and don’t want to use it, fine. But stop pretending that no one can give you good engineering reasons that justify it’s existence.
Anyway I’m not entirely sold, I feel good old Sass is way better than styled components and Tailwind, but only in right hands. It’s painfully easy to write unmaintainable styled components and Sass/CSS.
With regards to bloated HTML, that might seem the case but since you reuse the same class-names everywhere in your app (and tailwind JIT removes non-used classes), compression really cuts down on the size of your bundles. It just looks bloated in the web inspector. This is a disadvantage, it is a bit hard to debug HTML with all those class-name strings around, although I would say web-inspectors should just truncate "class" attr value
With bundler performance it adds some overhead (tailwind has to go through all your .js/tsx files), but in my experience not noticeable
The sad reality for me: I am very very productive with a mix of inline styles and Emotion/Styled-Components! I genuinely enjoy writing CSS. A library like MUI gives me a foundation of consistency and helpful utilities, but I love the ability to drop back into CSS and express ideas in a universal styling language that any experienced frontend developer should be able to understand. I move fast. I can show my code to others for feedback and they’ll be able to contribute. I genuinely enjoy it.
Tailwind does offer some ways of writing CSS but my understanding from the docs is that they are discouraged. They certainly don’t give the ease and quick feedback of in-line or Emotion.
I’m also highly suspicious of the longevity of the utility class approach and its shorthand. It makes me think of my experience with Slim templates in Ruby: it felt like a force multiplier at the time but but only other initiates appreciated it and it looked like absolute gibberish when I came back to it years later. These projects would have been better sticking with ERB since it’s the HTML everyone knows sprinkled with Ruby where needed. My initial impression of Tailwind is the same: “this looks crazy but everyone swears that it’s a breeze once you learn the syntax!” Will the end result be the same?
Again, no disrespect to anyone who enjoys it. I fully recognize the many drawbacks of inline styles and Emotion, particularly around performance. I’m currently lamenting the incompatibility of Emotion and React Server Components. I plan on giving Tailwind a fair shot soon and I’m open to having my mind changed, but I do hope it has more staying power than Slim templates.
In comparison, my experience with adopting TypeScript was one where my initial skepticism was met with people clearly explaining the benefits of using it. And TypeScript has a similar aspect where you need to try it to really understand its benefits, but it also has clear value propositions that can be described and considered on their fundamental merits. Tailwind does not seem to have the same kind of benefits, so the arguments boil down to variants of "with us or against us" and "look at all these people using it." And from that perspective, I see a lot of people who I respect a lot who are _not_ using it. Whereas I never saw many experts saying "TypeScript sucks don't use it" - they just quietly adopted it because type safety was important to them on its merits.
But Tailwind works for me because:
- it gives good defaults (from sizes and distances to color palettes)
- it's documentation is heavenly, and helps you find the precise thing you're looking for in seconds
I actually leveled up my understanding of CSS thanks to Tailwind :)
Honestly, as much as I disliked the CSS-in-JSS trend, it did solve a reasonable problem with React — one which Vue and others had solved with their SPC.
It feels like ducktape on top of ducktape...
If Vue/Svelte had gotten the popularity React has you would see a lot more people realizing that SFCs and scoped style blocks solve most of the problems people poorly solved with CSS-in-JS.
Tailwind has some other benefits to it like good token setup and ability to copy paste from project to project and have it just work, but the mess it makes of your templates and the difficulty of then editing it down the line doesn't make those benefits worth it.
React is just the most prominent of them all.
For the amount of time that a typical web app lives, raw CSS is just a resiculous waste of time that sucks the joy out.
> create-next-app now asks if you want to start with Tailwind CSS instead of CSS Modules.
Tailwind is super successful from people that have an aversion to React. Like all my mostly backend devs friends.
Steve was the personal designer for Taylor Otwell and Laravel long before Tailwind. Steve has created all the most recent Laravel designs for many years.
Prior to starting Tailwind with Adam, Steve wrote up a bunch of fronted design standards and published a book called Refactoring UI. In that time frame, he also created a bunch of free open sourced sets of SVG icons called HeroIcons. HeroIcons were a direct replacement and improvement over Font Awesome.
Somewhere in that timeline, Adam and Steve put everything they had created together into a single project, and that was called Tailwind CSS.
Being on the ground floor of Laravel and the open source community totally helped with their initial exposure. All the things I mentioned above were also popular topics here on HN a year before Tailwind was created.
https://www.refactoringui.com/ https://heroicons.com/ https://twitter.com/steveschoger
I personally met him pre COVID at Laracon, Chicago. I bumped into him during lunch, and he was super cool and open to chat.
I have no affiliation with him, and have only followed him on Twitter after we met.
CSS is a tool as Jeff Atwood would say designed for pit of despair[1]. Which means, the default path is making mistakes and failing horribly.
And Tailwind CSS is a tool which is designed with Pit of Success in mind. This means, the default path is success and not anger and despair.
Not to mention, it doesn't have any performance taxes. And also, unlike other CSS framework, you should know CSS in order to utilise Tailwind CSS properly. People learn more about CSS by using Tailwind unlike many other CSS frameworks.
[1] - https://blog.codinghorror.com/falling-into-the-pit-of-succes...
I’m just going to say that Tailwind, IMHO, is the best thing that has happened to CSS.
It’s by far the simplest and cleanest abstraction of CSS, and it accomplishes a lot through a very straightforward implementation.
At this point I can’t see myself writing CSS in any other way.
But, but, but, seems like almost all the project that use tailwind ends up looking like linear. Not that I blame tailwind for that, there was an era when almost all bootstrap projects looked similar, I think it is the same thing.
With tailwind, is there an easy way to start with a nice simple working responsive site that I can tweak?
Thanks Adam and all the Tailwind contributors for your work!
I wrote about it in a more detail:
Sometimes, they are, and should be, separate. But in other cases, styling is related to the content, or part of it.
You have a card? Boom, you need to couple styles for the title, for the content, for the footer etc.
You have a form? Boom, you need to couple styles with the form.
The idea that styles are somehow decoupled from content is funny idea that very rarely works out in practice.
Would you copy paste around:
<form class="asd fasdf e4rwe sfdg sdfgbbv cxvbxcs asdf asdf wer wer gfdghdfgh fgh">
20x around your static website and keep it updated manually when someone "from design" wants to change the "form" look?
Or would you just <form class="classic-form"> and describe the style of that class of form in a single place?
I know what I'd do. :)
My argument is that React is actively bad for writing HTML/CSS, and therefore people came up with clunky solutions to get around those limitations. Certainly Tailwind is more than just a solution for React, but a large part of its popularity is due to it.
Why do people keep mentioning Tailwind and CSS-in-JS in the same sentence?
And no, Tailwind would still have its place even if Svelte appeared first because instead of writing the same styles everywhere you'd still want to extract them into a file, and have sensible defaults for them.
Oh look, Tailwind does exactly that.
Because one of the biggest arguments for each is scoping styles to a component instead of the default global cascade.
> And no, Tailwind would still have its place even if Svelte appeared first because instead of writing the same styles everywhere you'd still want to extract them into a file, and have sensible defaults for them.
Writing same styles everywhere? I'm not sure I understand what you mean, that isn't related to Tailwind or frameworks. Sensible defaults are just design system tokens, those are usable in way more styling approaches than just Tailwind.
I'm not saying Tailwind wouldn't exist, I'm saying it wouldn't be as wildly popular as it is now. React's lack of CSS features has encouraged a generation of frontend devs to simply not learn CSS fully. Sure you need to know some CSS to use Tailwind, but in many cases people just copy-paste Tailwind templates from elsewhere (another benefit of Tailwind) and don't actually understand the styling. I see Tailwind classes that do nothing in the wild all the time.
Escaping the global cascade has been on everyone's mind since forever. BEM, one of the lost popular ways to try and scope CSS to components, was invented in 2006: https://en.bem.info/methodology/history/
OOCSS is 2009: https://www.slideshare.net/stubbornella/object-oriented-css
> Writing same styles everywhere? I'm not sure I understand what you mean,
You need to specify things like font sizes, line heights, border styles, colors etc.
> React's lack of CSS features has encouraged a generation of frontend devs to simply not learn CSS fully.
This has nothing to do with React. No one ever learned CSS fully. If anything, Tailwind encourages you to learn more CSS.
> but in many cases people just copy-paste Tailwind templates from elsewhere (another benefit of Tailwind) and don't actually understand the styling.
How different is it from all the history of the web?
Feedback welcome
So we have known all along that this will never happen. It was rejected for some very good reasons before Tailwind began.
The internals are still CJS, but at least we can use it ESM.