I used the JIT version recently on a new landing page with code completion for class names in my IDE and found it great. The distance between what I'm picturing in my head and what I have to type to see that on the screen felt so much shorter and less fatiguing than the standard CSS approach.
With the regular way, to style something that's probably not going to appear elsewhere, I'm having to: come up with class names, annotate the HTML with them, repeat some of this annotating in a CSS file, jump back and forth between files to tweak the styles, use the web inspector to figure out which CSS class is overriding another then jump to the right CSS file to fix it etc.
Tailwind classes are also faster to type and flip between when you're experimenting (e.g. editing "mt-5" to "pb-3" vs "margin-top: 4.25em" to "padding-bottom: 2.75em") and you get less distracted because it has sensible defaults and helpful guardrails (you rarely need all the possible attributes and range of parameter values CSS has available).
I also rarely had the super irritating and common CSS scenario where you edit a style and it doesn't change and you have to go investigate to find out why e.g. something is overriding something, your selector is wrong, and even after all that maybe you undo the edit because it doesn't look good. Plus you no longer have the fear that tweaking a shared class to going to break some completely different page.
I feel that beyond some building blocks, trying to create reusable CSS classes with cascading styles has similarities to using excessive abstraction and deep OOP class hierarchies in regular programming languages to avoid a little duplication.
I also don't have a problem with styling stuff appearing in my HTML files either as long as the right HTML tags are used around the data. HTML files are already full of class annotations and divs that are only there for styling yet this doesn't cause a problem to e.g. browsers, screen readers or crawlers.
> I used the JIT version recently on a new landing page
Yeah, that's kinda the poster child use case for Tailwind and similar frameworks. Landing pages are all about being jazzy and unique and eye catching, and not so much about code reusability/composability.
Where it gets less fun is when you want widget consistency across multiple areas of a site and across design tweaks over time, since now you have to deal with several `class="..."` strings across multiple files, possibly with class names in arbitrary order, possibly mixed with logic from other templating languages (be it from Django or JSX or whatever). So you can't just grep to achieve the objective of changing styles in one place to affect all instances of some semantic group.
Personally I think comparing Tailwind directly against traditional CSS as a whole is painting in too broad strokes. There's a lot of CSS methodologies and also a lot of bad practices (e.g. using SASS indentation as namespacing mechanism and then running into the old problem of specificity), and comparatively, there's a lot more than Tailwind in the atomic CSS space, and more broadly, in the compiled CSS space.
Utilities like Bootstrap (e.g. `class="btn btn-primary"`) for example share many benefits of both atomic CSS and "good" subsets of traditional CSS practices (namely, you get memorable short class names, which are also organizable along semantic lines). So there's definitely more shades of gray than just "atomic-css-is-the-best-thing-since-sliced-bread" vs "looks-like-lazy-style-attributes-lol".
In the context of component based development, react etc., I believe what you describe is actually very beneficial. Think about a case where instead of doing something <button class="btn btn-primary"> you write an atomic component <MyButton> which uses tailwind internally.
With this workflow:
* There are no global styles that can have an unknown or unexpected impact on the application when modified.
* The component's style is completely encapsulated. It can be placed anywhere in the application without worrying about inherited styles causing problems.
I am going to give it a try. The argument against using it is that it defeats the purpose of Tailwind, but I think its useful to start by spraying classes until things work and then moving those classes into e.g. btn-primary once the styles become stable and need universality.
We recently started using a combination of tailwind and BEM instead of bootstrap.
It means that we can have our own custom "button button--sm" classes - a single place to change general styling - and on top of that get all flexibility of the tailwind utils for edge cases.
I don't think it's perfect, but it's so far much more flexible than bootstrap, and we don't need to duplicate loads of classes for each similar component.
> Yeah, that's kinda the poster child use case for Tailwind and similar frameworks. Landing pages are all about being jazzy and unique and eye catching, and not so much about code reusability/composability.
It doesn't matter, you can have an entire newspaper and perfectly done in functional css with incredible results without having to mastermind any architecture.
The trick with CSS is to write semantic HTML and avoid div, span and css classes. You can of course inline css too (used mostly for optimization to prevent layout shift, but is also fine for elements/classes that are not repeated, such as the top menu, top banner/intro and header/footer)
> The trick with CSS is to write semantic HTML and avoid div, span and css classes
This experiment has failed though. CSS isn't powerful enough to style HTML however you want without having to add a soup of extra divs and classes that are only there for styling. No large website today works otherwise.
HTML is still semantic when it contains styling markup (in the sense that a computer can read and understand the structured data from it) so I'm unclear what benefit is being missed out on. Whether you call a class "home-cta-subheading" or "text-center" so you can apply some styles doesn't make a difference to screen readers, browsers or search crawlers either.
I agree. I think the real crux of the issue is that people find CSS hard, and are embarrassed about finding something that's "just a style sheet" hard, so they flock to more complicated alternatives.
I'm really glad I just powered through that point and let myself feel dumb.
what does semantic html has anything to do with css. Doesn't this make the look and feel of the page easily break on any change on the markup structure and content?
Also does this comment even has a point? Like if we do what you suggest then no need of tailwind?
I tried Tailwind (and a similar project Windi) on a few projects now and have some findings.
Tailwind aggressively speeds up development time of components by allowing me to stay in the same cobtext when styling things. The brevity of class names also dramatically shortens the time spent writing styles. While working on the projects I'd setup with Tailwind, I felt far more productive.
However, those were new projects. After completing them and needing to go back and modify or maintain them, the experience has been horrible. The resulting style declarations (as class names) are completely unreadable and unmaintainable. I've tried organizing them and splitting class names onto multiple lines, but it has only cluttered things.
In my experience, Tailwind (and similar projects) produce styles that are effectively read only. They are superb when writing a new component and styling things from scratch, but maintenance is nonexistent.
Because of this, I've now switched to using a CSS-in-JS solution to gain the benefits of in-context styling and still have the ability to write CSS declarations in a structured and maintainable way.
We use Tailwind at my work and I personally find hopping into the template of a file I've never been in before super easy with it. With normal CSS I've usually got an HTML file and a CSS file side-by-side in my IDE, and I'm cross-referencing awkwardly-named classes in the template with a stylesheet. Sometimes these styles might be coming from a local, dedicated stylesheet, sometimes they might be coming from a global stylesheet that I might end up needing to grep through the project for in order to find where these styles are coming from.
With Tailwind, I see a <div>, and I see all the styles on it, right within the template. I don't need to follow class names, or cross-reference between files, it's just there, where I'm already looking.
I'm very surprised that people actually like tailwinds.
I wrote HTML in a time when you used inline HTML attributes for styling. Changing one bit of the style meant visiting every single page to update everything (then making sure to test because you definitely forgot at least one place).
CSS was an amazing idea for making just one place to put all your styling. You could now change one style and everything else would automatically update.
Tailwinds feels like it's just a trip right back to the old inline styling right down to searching bunches of pages if you're making a styling update.
Why not use both? twin.macro is an excellent library that compiles Tailwind (and adds additional, useful variants) in systems like Styled Components and Emotion, so you gain the benefits of quick component creation, but the same pleasant maintenance of colocating utilities and styles/classes/objects composed of these utilities with your components.
It's been an absolute dream in a decent-sized project so far, and even with some refactors.
Regardless, it's not everyone's cup of tea, but depending on the UI framework of choice and the flavor of CSS you use, YMMV when it comes to dev experience.
In Vue or Svelte, I wouldn't even use a CSS-in-JS solution because vanilla Tailwind to compose utilities into localized classes is a straightforward approach.
If you're using Svelte, you don't really need Tailwind (but are obviously free to use it), especially if you're using your own components.
Svelte's styling is already pretty atomic as it is.
With Svelte, I use a small global reset, and a global file containing native CSS variables (which I reuse across multiple projects).
Most of my Svelte CSS is component specific (and in most cases, no classes are even necessary) and they can be themed by simply referring to the CSS variables in my global variable file.
I found exactly the same with my brief experience with Tailwind. Great fun to write, couldn't make head nor tail of it when I came back a few weeks later. Perhaps this changes if you use Tailwind day in day out though!
I've stuck with styled-components for now, though I confess that I've started to wonder if the the verbosity of creating a (styled) component for everything, passing props, etc. is a bit excessive since trying Tailwind.
The only thing I appreciate Tailwind for is that I started to dig deeper just to have even stronger hesitation against it, so I believe I've saved a lot of hours in my projects just by not using it. But it also got me stumbling upon solutions based on the CSS global variables and that's what I think is the CSS next big thing. They allow to stay with CSS within CSS layer so no leakage to HTML or JS.
I'm not sure I get Tailwind still. Doing everything with utility classes and OOCSS / BEM are things we stopped doing literally decades ago. CSS modules still seem to solve every problem Tailwind solves, and better. CSS modules combine the power of global utility classes with locally styled components/locally scoped classes, and compile to static stylesheets, a requirement for performance. I'm not sure how Tailwind works, but any CSS that's built at runtime and JS and inserted into the DOM dynamically should be avoided, and is an example of favoring developer experience over end user experience. It's always surprising to me when the build process isn't front and center of any CSS framework, since that's the most important performance aspect. I'm not concerned about Tailwinds verbose CSS use since that's gzipped away, but the static stylesheet compilation aspect worries me if it's not front and center of the framework.
CSS modules let you use the full power and control of vanilla CSS, without having to worry about styles bleeding across components. Sprinkle in your global utility classes for your design system and you're good to go. Or sometimes even better, abstract design into components like `<grid>` `<column>` etc and not even worry about the classname implementation.
I know I'm missing part of the picture, because of the hype and joy that people report from Tailwind. What part(s) am I missing that move folks from the power, beauty, and simplicity of CSS modules, to all-utility-classes-all-the-time Tailwind?
Seems like you are basing your opinions on some misconceptions. Let me try to clear that for you.
"CSS modules still seem to solve every problem Tailwind solves, and better."
- Not necessarily true. Unlike css modules, tailwind removes the whole "think about a name for your class" mindset, reducing friction from the development process. It also unifies some base level design decisions like spacing and colors, which developers would have to rely on "best practices" otherwise, which don't necessarily get strictly enforced.
"I'm not sure how Tailwind works, but any CSS that's built at runtime and JS and inserted into the DOM dynamically should be avoided, and is an example of favoring developer experience over end user experience."
- You are right, looks like you are not sure how Tailwind works. Tailwind does not build anything at runtime, it all happens at build time. Tailwind will compile only the things you need (using the new JIT mode) into a css stylesheet which is sent to the frontend. Not much different from how sass or scss works.
"CSS modules let you use the full power and control of vanilla CSS, without having to worry about styles bleeding across components."
- Tailwind does not stop you from using vanilla css, but in most cases you do not need to. As per their website, you can think of it as an API to use parts of CSS, instead of CSS replacement. I think you are confusing Tailwind as a replacement for something like CSS Modules, but those two are completely unrelated. You can still use CSS Modules while using Tailwind. Think of it as an api to your design sytem just like you could think of an ORM as an API to your database.
Aside from all of this. Try to use tailwind for 1 side project. You’ll see the difference of productivity when you remember most of the tailwind classes as opposed to having to open another css file, create a class, then reimport them.
JIT mode basically means it recompiles your styles before you can press reload on your browser.
Before they didn't have all colors enabled by default, because generating classes like `bg-blue-500`, `text-blue-500`, `border-blue-500`, etc. for all colors would increase the resulting CSS way too much. They did the same thing with variants.
With the JIT none of that is necessary anymore. Plus you can use arbitrary values because it's being compiled now.
The other thing is, building css the traditional way, after refactoring and renaming things a bit, I usually end up with something that looks very similar to tailwind syntax anyway. So might as well have a flavour of that we can all refer to and agree on than each person having their own set of utilities and naming conventions. That way I don't have to explain or write elaborate comments - I can just point the person to the tailwind docs. So it solves that kind of problem for me.
> You can still use CSS Modules while using Tailwind
Recommended even. I use Tailwind with CSS Modules as a fallback when there's simply no way to achieve the result using Tailwind (rare) or it's prohibitively complicated/messy.
Also for CSS hacks if you need to support an older browser.
Based on what you've said, you're right, you don't understand it...the things you're comparing it to don't really make sense. Bem doesn't make sense to compare and neither do css modules. Tailwind is a stylesheet with css classes that do atomic things like changing border radius. It gives you a set of classes that allow you to build just about anything you need with just classes. When you compile an app that uses tailwind, it takes just the styles you use and puts them into a single stylesheet. So all of the things you claim to be wrong with tailwind aren't true. Tailwind is very performant because you only use the styles you need. It uses css variables for theming so there's no need to implement it in userland. It also uses css variables to do transforms which is very important because transforms are not additive in css yet. Even if you don't end up liking tailwind, the thing is executed really really well from the ground up.
I think Tailwind is multiple very different ideas in one library. One thing that Tailwind is is a set of primitives and design tokens that’s just slightly higher level than CSS, but still lower level than a component library. I think it’s pretty good at this.
Another thing that Tailwind is is an opinionated delivery mechanism for your styles, in this case, as utility classes that can go straight into your HTML. This is probably a big cause of Tailwind’s popularity, not because any one person necessarily loves using classes, but because it makes it extremely easy for everyone to start using Tailwind in nearly any imaginable web project starting at plain static HTML files and going up from there. This aspect of Tailwind is something I’m not a huge fan of. To me it feels like a step back from a lot of higher-level CSS tools (like many CSS-in-JS libraries) to just go back to concatenating magic string literals into my UI code. All the official Tailwind tooling (AFAIK) either just watches your codebase looking for these magic string and generating the appropriate raw CSS, or doing it in real-time with their new JIT compiler (which I admittedly haven’t investigated yet).
I agree with this. I think the "set of primitives" part is an interesting, perhaps great, idea. Makes it easy to enforce consistency across your codebase. But I don't like the delivery mechanism--chucking all the styles in with the markup feels like it makes everything hard to read: the HTML/component declarations are harder to read both in code and in the browser, the individual classnames are hard to read (both because the names chosen are often gibberish and because parsing a dozen of them in a row is difficult), and the styles are annoying to debug in the browser (now you have to scroll through a dozen different utility classes to figure out what's going on).
Personally I feel like a better approach is taking that same philosophy of design system primitives and executing it via something like SASS mixins, paired with single-file components à la Vue or Svelte. Then you can use better names (no need for brevity now), keep the styling separate from the markup (but still paired with it), and have a better experience debugging in the browser.
what do you think "high level" css-in-js libraries do if bot string concatenation, just watching your codebase with magic strings and generally ng raw CSS?
> CSS modules still seem to solve every problem Tailwind solves, and better.
I agree with most of what you're writing, but in arguing this out with people who seem to be enthusiasts, what I think I've discovered is that while there are existing (hell, longstanding) unbundled technical solutions fully capable of solving the problems Tailwind does... they don't solve the practical problems of channeling a group into a good-enough design system, and in fact many people who've been doing CSS have never actually really used a design system (especially if their experience is solely recent, and definitely if their experience is only incidental in the sense that they're application devs first). And many organizations don't have roles where someone can focus on solving this problem.
Just-add-Tailwind may hit an interesting pit-of-success spot for a lot of people in this position, where TW provides the atoms of the design system to scatter in a just-in-time manner. Sure, not elegantly, but practically.
Personally, I'd prefer to work with people/orgs that don't see this is an optimum, but I might accept it as a situational local optimum.
Tailwind is great if you're a startup, or someone who is a webdev and also has to be the designer. But in a large organization, with a company-wide style book, and a design department, it's not a good fit.
Tailwind works for "I see this control in my head, and I'm going to code like this to make it happen." It's not really a good match for "I see this control from the design department, and I'm going to make it fit into the rest of the site codebase like this."
Let's be honest, there isn't much elegance to the non-Tailwind solutions either. At the end of the day it's text input used by a rendering engine to style layout, it and your customers don't care how it got there.
Tailwind is global utility classes too. There’s no runtime aspect. It’s literally just css classes. The nicest thing is that all your variations exist, so you can do things like hover:font-bold. So you can see the rules immediately like with inline styles, but they’re more flexible.
At least finally someone using the dirty word "inline styles". It's like all the other comments here stepped right over that point from the grandparent. Only it's not inline styles, it's inline styles and you are Dennis fucking Ritchie in 1970 and your fingers hurt from the teletype so you are making up crude abbreviations for everything.
Side note, most of the time you don't want to make a font bold on hover as most fonts this will increase its length to account for increased stroke width. It doesn't transition well either.
I'm in the same boat. Started using Vanilla Extract (https://vanilla-extract.style) earlier this year and it's the best CSS setup I've ever worked with.
> CSS modules still seem to solve every problem Tailwind solves, and better.
I don't understand Tailwind either; but I find myself struggling with CSS modules when I need to override a CSS rule of a child from a parent. Like, say, my button should always be green, except in this context I want it to be purple, its font-size larger and its padding a bit different. With CSS modules, the parent component is unaware of the class name of the child component; so it cannot target that. Perhaps this should all be done with CSS variables; but then hell, how many CSS variables should my components expose? and besides, I am not even sure even they will completely solve this.
I don't personally care for Tailwind, but I get the reasoning why people gravitate towards it: just as modern JS moved away from inheritance to composition, so is CSS.
There's a fundamental argument that inheritance is a mirage and things in large projects become much simpler with composition-based approaches. You don't really need to grok the inheritance chain with Tailwind in the same way you do typical CSS.
For my personal projects I'd continue writing my own CSS... but for teams, I'd go to Tailwind without a second thought.
> Doing everything with utility classes and OOCSS / BEM are things we stopped doing literally decades ago.
I don't understand what you mean by this. Literally decades ago would take us back to at least 2001. OOCSS, BEM, etc. were all created after that year. Wouldn't it be correct to say "Doing everything with utility classes and OOCSS / BEM are things we hadn't even started doing literally decades ago."?
just got parachuted into a tailwind project. have to say I don't fully get it.
the major stumbling block has been how tailwind is mostly just css translated into its own hard-to-memorize lingo.
For example, say I want to do something basic like "display:flex; justify-content: start".
In tailwind you would type "flex justify-start" instead.
Which doesn't really follow any rules as far as how to get from A to B, so it's just a matter of having to look the magic word up in their docs each time until you memorize. And there are a lot of keywords (many modifiable according to n-dimensional properties) to memorize.
I know there are handy slugs like "w-1/3" that encapsulate a best practice - but I'm a person who'd rather master the underlying mechanics of that best practice and be able to deploy, tweak and debug it myself.
Coming up with variable/class names is one of the most annoying aspects of programming, so any way we can eliminate that task I think is always going to be a productivity boom
that gets long - especially if they are rendered inline, hard to scan through.
I'm often in a cycle where I am tweaking a complex class with 10-20 properties including flex, transforms, animations, etc. - and having them each be on their own line (and the class being in a separate file along with its parents, siblings and children, frankly) is key for readability to me.
I guess in the end I have come to have enormous respect for CSS as a powerful, mature language and I'm not looking to be buffered from it.
The beauty of it comes when you're working in a team of say 5 other front end devs of varying skill levels. There tends to be a large amount of duplication & overlap, people have different ways of doing things and achieving certain looks. If everyone agrees to use tailwind, you stop people from writing custom code which is ultimately a good thing because custom code requires custom comments and custom documentation etc which let's face it - nobody does or wants to do and even if they do, it's not maintained to the sort of standard tailwind docs are.
Not to mention, if your css isn’t scoped (and let’s face it, this is one thing traditional css sucks at) you just never quite know what rule some developer has put in somewhere at what else it effects.
> the major stumbling block has been how tailwind is mostly just css translated into its own hard-to-memorize lingo.
This is the only problem of tailwind, it relies on its own lingo, as all the OOCSS/BEM projects. When you involve semantics, you will always bring these kind of problems.
Spot on. Whenever you add a DSL like this, you need to carefully weigh costs and benefits. A hidden downside is that every new person who views your code base (And you in the future!) has to become proficient with the DSL. The base tech it wraps (HTML + CSS) is more fundamental; less overhead.
Another way of saying this, is that Tailwind adds cognitive overhead.
In my experience it's because any web app with complicated styling rules tends towards this anyways, except all the CSS names are custom, undocumented, and duplicated. The main tradeoff is that the CSS names are not domain specific, but honestly that's worked fine for me.
I hear you. I don't understand the reasoning behind frameworks propensity to abbreviate things, especially at "atomic"/utility levels. I think it partially stems from wanting to prevent ignorant knee-jerk reactions like "hurr durr why not just write inline styles".
I wish framework devs would just hyphenate (or even colon-ize) the CSS property names fully like "display-flex justify-content-start". I think Bootstrap does their own pattern like "d-flex", but all that does is require one to visit the docs to view some less common properties. Autocompletion pretty much makes typing these a breeze, and having less opinionated patterns for property names will make it less painful transitioning between frameworks.
One thing to consider is that being a bit more terse in tailwind is good because you effectively end up with media queries, dark mode, hover states etc all placed together.
> the major stumbling block has been how tailwind is mostly just css translated into its own hard-to-memorize lingo.
Autocompletion in your IDE makes this easy (the class names are similar to the CSS attributes, even in your examples, so you can usually guess them) and you use the same classes over and over again so you learn them quick. I barely spent 10 minutes in the Tailwind documentation the first few days because of the VSCode extension.
ah yes - that would be a big help. alas I am not a vscode user. I use webstorm and haven't been able to figure out how to get tailwind autocomplete to work with it.
Try using an IDE extension for autocompleting Tailwind's utilities based on your tailwind.config.js.
Twin Macro is a great wrapper library for Tailwind-in-JS with strong IDE support and it autocompletes all my utilities. I barely have to type anything to style everything in my project.
I can even hover over utilities to peek at its raw CSS.
I don't do frontend except when I have to and "flex justify-start" is way easier for me to learn and explore with than "display:flex; justify-content: start"
And the keywords all seem to make sense to me? It's "n-dimensional properties" but the dimensions are pretty consistent...
You have to learn the more verbose CSS properties in the first place, and the vast majority of tailwind's class names include the unique keywords of those anyway.
I'm ambivalent about Tailwind, but I've used it a lot. I will say the hypothetical advantages are mostly the following:
1. It's a step function over CSS units. This is the biggest strength, just standardizing that your design uses padding of 2, 4, 8px, but not 1px, 3px, or 1.23123em :). It provides more steps than you need, but still it's good that the core of Tailwind is a design system with defined unit and color variables.
2. Some of the utility classes are very helpful. Even as someone who likes writing CSS, it's nice to not need to give something a custom classname just because I want to put margin-top on it. class="mt-4", done.
I think the problem is Tailwind goes too far and tries to replace EVERYTHING with a stack of utility classes.
This works okay in extremely componentized web apps. It's a nightmare if your UI isn't highly componentized. I've seen projects where you make a button by copy pasting this ~80 character string of tailwind classes all over the place, and then changing the color names if you need to. Good luck fixing that when the designer decides that we don't want any buttons to have rounded corners anymore.
Personally I think the best parts of Tailwind are captured in Pollen[1], but I do wish it came with a subset of utility classes for colors, font sizes, margin, padding, and text alignment. I think the hard part is defining which subset is the right subset... I doubt you could find strong agreement from a large majority of developers on that.
>This works okay in extremely componentized web apps. It's a nightmare if your UI isn't highly componentized. I've seen projects where you make a button by copy pasting this ~80 character string of tailwind classes all over the place, and then changing the color names if you need to. Good luck fixing that when the designer decides that we don't want any buttons to have rounded corners anymore.
That app is done wrong. If you are using the same styles to represent a button you should use postcss and do
Yes, there is a right way to do it. But in the code I've seen in the wild, people are often not doing it right and those 80 char strings of utility classes are on the low side compared to some of what I've seen. I'm skeptical of Tailwind not for its own sake but because a lot of (most?) shops do not have the discipline to use it effectively. And what you are arguing here is basically a no true Scotsman defense.
I agree. I used Tailwind for roughly six months on a few projects before I noticed that I was only using the basic utility classes. I didn't like all the screen sizes and state "bloat" classes so I decided to take the best parts (margins, padding, background, font, text alignment) and create a simple CSS framework.
I've been working with CSS for over twenty years, and Tailwind is the way forward for me. Some of the big benefits are:
* No more worrying about naming class selectors. This frees up so much cognitive space. The less you have to worry about naming the better. I used the SUIT CSS naming convention before, which allows a mix, and that just creates friction. You need the same level of abstraction all the way through.
* No more flipping between files. You edit your styles directly in the HTML. You will need to consult the TW docs, of course, but they're easy to navigate.
* Tailwind is more than just inline styles. It provides a nice syntax for targeting breakpoints and little utilities for conveying more abstract styles/stacking rules.
* TailwindUI is a great way to jumpstart a project and looks way better (IMO) than Bootstrap's components.
* JIT is awesome
I'd be remiss if I didn't mention some cons:
* Looking at a bunch of class names in your HTML is at overwhelming at first. It's hard to delineate the structure. Using proper HTML elements, roles, etc. helps.
* You will need to DRY up your repetitive styles by moving things to templates/components. So you still have to name things, but just keep it generic (alert, dropdown, badge, etc)
* Sometimes you'll have to create class selectors when working with web frameworks and JS libs that require a single class selector option.
I can just add that WindiCss is worth testing. In my small trials it worked a lot better than Tailwind with jit. Windi with Vite gives me a really fast dev experience.
I've been a Bootstrap user for a long time, but I recently made the jump to Tailwind. It's not the revolutionary upgrade I was hoping for, but it's nice evolutionary step in the right direction. It's quite intuitive, but it doesn't get rid of most of the frustrations that come from doing layouts, as those come from the design of CSS itself. `@apply` makes the upgrade worth it though, it's easy to make custom classes from the Tailwind elements.
The one thing I don't like is that the culture around Tailwind seems a lot more proprietary, like you're getting three quarters of a product that you need to buy the rest of, whereas Bootstrap felt like you got everything you could ever need for free.
If you're talking about Tailwind UI[1] — I use Tailwind extensively and have basically never looked at Tailwind UI. It's just useful snippets of HTML styled with Tailwind. It is by no means required to get value out of Tailwind.
I'm not sure what you mean by proprietary culture! Based on the fact that I've pretty much never seen anyone talk about it, I would guess (total guess, no real knowledge) that no more than 1% of Tailwind users have paid for Tailwind UI.
You have to do literally everything from scratch with Tailwind though, for example I never realised how much work is involved in a simple avatar dropdown / logout component (hidden full-screen button). Tailwind is much closer to raw CSS than Bootstrap. That's not a criticism, it's just a different value proposition.
That's what I mean, though. $250 for some styled HTML! I think that's crazy. Compare with Bootstrap, which has basically just as many snippets simply as part of the documentation.
It seems proprietary because there are ad links disguised as documentation links. You can't click "Components" anywhere on TailwindCSS.com or you'll end up on TailwindUI.com pricing page.
It's fine that they want to make money but it's very confusing for a new user. Ultimately, they might make more money by dropping the shady links if it's turning away enough new users.
I can maybe see how that could potentially be confusing to a brand new visitor, but how is it shady? It's a clearly labeled link that does take you to components made with tailwind. Are they supposed to link to all the freeware out there first?
Just started with tailwinds and similiar thoughts. A framework like this without components.
Try daisyui as a tailwinds plugin. It comes with the missing components. It also allows you to replace your 80 character style for buttons with btn btn-primary.
There is a dead sibling comment which I will repeat with a bit kinder words, and with a different caveat.
As a frontend developer I don’t like Tailwind for several reasons, it brings the styling into the structure. As a frontend developer Tailwind is at a forefront of what I would consider bad practice and encourages a code style which would be a nightmare for me to maintain.
That said. Tailwind seems to be loved be people who are not professional frontend developers. It seems to be just the right tool for people who are not necessarily proficient in CSS. And perhaps people like me (and the dead sibling) need to learn to let go and allow other people to have the tools which makes it easier for them to do the job which they are not experts at. For that reason I understand Tailwind, even though I don’t agree with it.
I think TWCSS' argument is that we always were bringing the styling into the structure.
Show me a site that has CSS Zen garden style replaceable stylesheets that totally overhaul the nature of the site. It's incredibly rare and almost always not worth the effort. What business says "I want to overhaul the styles of my application but change no structure at all. I'd posit it's near 0.
Even if that's your goal, and I'd argue that it shouldn't be, you can still do that with TWCSS and the @apply keyword. You can write your generalized names then apply whatever twcss keywords you want to them separate from your
document's structure.
If your overhaul amounts to changing a "theme" you can easily do that with twcss. In fact, that's basically the point.
I am a professional frontend developer and I love it.
I have said it many times, but I'll have a go at it again.
The reason why inline styles got it's bad reputation is mainly because we used to have no way of building reusable components.
Nowadays, everyone and their mothers are using some kind of frontend framework that allows you to reuse components, so your inline styles can be mentioned once and used everywhere. It's not a problem anymore.
Pair your tailwind with styled components and you can finally reach the dream of semantic HTML.
I like Tailwind because it brings styling into structure. Dealing with external CSS has always been really challenging for me, and I've always heretically used inline CSS.
I mean header files are OK, and professional C developers probably love them, but not having header files is kind of great too :)
I think your comment has a lot of merit. Personally Tailwind has been awesome but I think it's because it makes all these abstractions for you. It also forces less experienced developers to follow this abstraction rather than making their own, which usually ends up as a ball of spaghetti.
I have a similar comment elsewhere in the thread but it applies here too, I think: the main drawback of Tailwind is that it's extremely general. I'd imagine a well abstracted, focused, domain-specific set of CSS created by experienced frontend developers will be much better within that domain.
I am a professional frontend developer working on a large-scale react application and I love tailwind. I am proficient in CSS, but having colocated html (well, JSX) and css makes so much sense, and the design system really helps fast iteration while also keeping things looking nice.
do you prefer the structure in the styling or the styling in the structure?
i prefer the later. with styling in structure if i make a change in one place, it effects the one thing i intended it to
with structure in styling, if i change one thing, it may impact many other things, some of which i might not intend to and are sometimes unknowable at the time of the change
With the regular way, to style something that's probably not going to appear elsewhere, I'm having to: come up with class names, annotate the HTML with them, repeat some of this annotating in a CSS file, jump back and forth between files to tweak the styles, use the web inspector to figure out which CSS class is overriding another then jump to the right CSS file to fix it etc.
Tailwind classes are also faster to type and flip between when you're experimenting (e.g. editing "mt-5" to "pb-3" vs "margin-top: 4.25em" to "padding-bottom: 2.75em") and you get less distracted because it has sensible defaults and helpful guardrails (you rarely need all the possible attributes and range of parameter values CSS has available).
I also rarely had the super irritating and common CSS scenario where you edit a style and it doesn't change and you have to go investigate to find out why e.g. something is overriding something, your selector is wrong, and even after all that maybe you undo the edit because it doesn't look good. Plus you no longer have the fear that tweaking a shared class to going to break some completely different page.
I feel that beyond some building blocks, trying to create reusable CSS classes with cascading styles has similarities to using excessive abstraction and deep OOP class hierarchies in regular programming languages to avoid a little duplication.
I also don't have a problem with styling stuff appearing in my HTML files either as long as the right HTML tags are used around the data. HTML files are already full of class annotations and divs that are only there for styling yet this doesn't cause a problem to e.g. browsers, screen readers or crawlers.
Yeah, that's kinda the poster child use case for Tailwind and similar frameworks. Landing pages are all about being jazzy and unique and eye catching, and not so much about code reusability/composability.
Where it gets less fun is when you want widget consistency across multiple areas of a site and across design tweaks over time, since now you have to deal with several `class="..."` strings across multiple files, possibly with class names in arbitrary order, possibly mixed with logic from other templating languages (be it from Django or JSX or whatever). So you can't just grep to achieve the objective of changing styles in one place to affect all instances of some semantic group.
Personally I think comparing Tailwind directly against traditional CSS as a whole is painting in too broad strokes. There's a lot of CSS methodologies and also a lot of bad practices (e.g. using SASS indentation as namespacing mechanism and then running into the old problem of specificity), and comparatively, there's a lot more than Tailwind in the atomic CSS space, and more broadly, in the compiled CSS space.
Utilities like Bootstrap (e.g. `class="btn btn-primary"`) for example share many benefits of both atomic CSS and "good" subsets of traditional CSS practices (namely, you get memorable short class names, which are also organizable along semantic lines). So there's definitely more shades of gray than just "atomic-css-is-the-best-thing-since-sliced-bread" vs "looks-like-lazy-style-attributes-lol".
With this workflow:
* There are no global styles that can have an unknown or unexpected impact on the application when modified.
* The component's style is completely encapsulated. It can be placed anywhere in the application without worrying about inherited styles causing problems.
edit: formatting
I am going to give it a try. The argument against using it is that it defeats the purpose of Tailwind, but I think its useful to start by spraying classes until things work and then moving those classes into e.g. btn-primary once the styles become stable and need universality.
It means that we can have our own custom "button button--sm" classes - a single place to change general styling - and on top of that get all flexibility of the tailwind utils for edge cases.
I don't think it's perfect, but it's so far much more flexible than bootstrap, and we don't need to duplicate loads of classes for each similar component.
It doesn't matter, you can have an entire newspaper and perfectly done in functional css with incredible results without having to mastermind any architecture.
http://minid.net/2019/08/12/in-defense-of-functional-css/
This experiment has failed though. CSS isn't powerful enough to style HTML however you want without having to add a soup of extra divs and classes that are only there for styling. No large website today works otherwise.
HTML is still semantic when it contains styling markup (in the sense that a computer can read and understand the structured data from it) so I'm unclear what benefit is being missed out on. Whether you call a class "home-cta-subheading" or "text-center" so you can apply some styles doesn't make a difference to screen readers, browsers or search crawlers either.
I'm really glad I just powered through that point and let myself feel dumb.
Also does this comment even has a point? Like if we do what you suggest then no need of tailwind?
Tailwind aggressively speeds up development time of components by allowing me to stay in the same cobtext when styling things. The brevity of class names also dramatically shortens the time spent writing styles. While working on the projects I'd setup with Tailwind, I felt far more productive.
However, those were new projects. After completing them and needing to go back and modify or maintain them, the experience has been horrible. The resulting style declarations (as class names) are completely unreadable and unmaintainable. I've tried organizing them and splitting class names onto multiple lines, but it has only cluttered things.
In my experience, Tailwind (and similar projects) produce styles that are effectively read only. They are superb when writing a new component and styling things from scratch, but maintenance is nonexistent.
Because of this, I've now switched to using a CSS-in-JS solution to gain the benefits of in-context styling and still have the ability to write CSS declarations in a structured and maintainable way.
With Tailwind, I see a <div>, and I see all the styles on it, right within the template. I don't need to follow class names, or cross-reference between files, it's just there, where I'm already looking.
I wrote HTML in a time when you used inline HTML attributes for styling. Changing one bit of the style meant visiting every single page to update everything (then making sure to test because you definitely forgot at least one place).
CSS was an amazing idea for making just one place to put all your styling. You could now change one style and everything else would automatically update.
Tailwinds feels like it's just a trip right back to the old inline styling right down to searching bunches of pages if you're making a styling update.
It's been an absolute dream in a decent-sized project so far, and even with some refactors.
Regardless, it's not everyone's cup of tea, but depending on the UI framework of choice and the flavor of CSS you use, YMMV when it comes to dev experience.
In Vue or Svelte, I wouldn't even use a CSS-in-JS solution because vanilla Tailwind to compose utilities into localized classes is a straightforward approach.
Svelte's styling is already pretty atomic as it is.
With Svelte, I use a small global reset, and a global file containing native CSS variables (which I reuse across multiple projects).
Most of my Svelte CSS is component specific (and in most cases, no classes are even necessary) and they can be themed by simply referring to the CSS variables in my global variable file.
I have created React components with TW, where the components are complex and large.
However, breaking them down into tiny functional blocks, maintenance is easier.
I've stuck with styled-components for now, though I confess that I've started to wonder if the the verbosity of creating a (styled) component for everything, passing props, etc. is a bit excessive since trying Tailwind.
CSS modules let you use the full power and control of vanilla CSS, without having to worry about styles bleeding across components. Sprinkle in your global utility classes for your design system and you're good to go. Or sometimes even better, abstract design into components like `<grid>` `<column>` etc and not even worry about the classname implementation.
I know I'm missing part of the picture, because of the hype and joy that people report from Tailwind. What part(s) am I missing that move folks from the power, beauty, and simplicity of CSS modules, to all-utility-classes-all-the-time Tailwind?
"CSS modules still seem to solve every problem Tailwind solves, and better."
- Not necessarily true. Unlike css modules, tailwind removes the whole "think about a name for your class" mindset, reducing friction from the development process. It also unifies some base level design decisions like spacing and colors, which developers would have to rely on "best practices" otherwise, which don't necessarily get strictly enforced.
"I'm not sure how Tailwind works, but any CSS that's built at runtime and JS and inserted into the DOM dynamically should be avoided, and is an example of favoring developer experience over end user experience."
- You are right, looks like you are not sure how Tailwind works. Tailwind does not build anything at runtime, it all happens at build time. Tailwind will compile only the things you need (using the new JIT mode) into a css stylesheet which is sent to the frontend. Not much different from how sass or scss works.
"CSS modules let you use the full power and control of vanilla CSS, without having to worry about styles bleeding across components."
- Tailwind does not stop you from using vanilla css, but in most cases you do not need to. As per their website, you can think of it as an API to use parts of CSS, instead of CSS replacement. I think you are confusing Tailwind as a replacement for something like CSS Modules, but those two are completely unrelated. You can still use CSS Modules while using Tailwind. Think of it as an api to your design sytem just like you could think of an ORM as an API to your database.
I just can’t go back without tailwind.
Before they didn't have all colors enabled by default, because generating classes like `bg-blue-500`, `text-blue-500`, `border-blue-500`, etc. for all colors would increase the resulting CSS way too much. They did the same thing with variants.
With the JIT none of that is necessary anymore. Plus you can use arbitrary values because it's being compiled now.
Recommended even. I use Tailwind with CSS Modules as a fallback when there's simply no way to achieve the result using Tailwind (rare) or it's prohibitively complicated/messy.
Also for CSS hacks if you need to support an older browser.
But I still prefer naming things to the class soup and the excessive repetition.
ITCSS (Inverted triangle CSS) works with the cascade and results in clean, minimalistic CSS files.
I do not build SPAs though and do get that quick styling works really well for that scenario.
I do import Tailwind colors, spacing and sizes in SCSS maps for easy access and do like the standardized approach.
1. It removes a layer of abstraction that's redundant if you use a component-based UI framework.
2. It provides constraints that act as guardrails against introducing inconsistencies into a design.
3. Its tooling is not magic and does not have runtime impact.
More detail at https://vincenttunru.com/why-tailwind/
Another thing that Tailwind is is an opinionated delivery mechanism for your styles, in this case, as utility classes that can go straight into your HTML. This is probably a big cause of Tailwind’s popularity, not because any one person necessarily loves using classes, but because it makes it extremely easy for everyone to start using Tailwind in nearly any imaginable web project starting at plain static HTML files and going up from there. This aspect of Tailwind is something I’m not a huge fan of. To me it feels like a step back from a lot of higher-level CSS tools (like many CSS-in-JS libraries) to just go back to concatenating magic string literals into my UI code. All the official Tailwind tooling (AFAIK) either just watches your codebase looking for these magic string and generating the appropriate raw CSS, or doing it in real-time with their new JIT compiler (which I admittedly haven’t investigated yet).
Personally I feel like a better approach is taking that same philosophy of design system primitives and executing it via something like SASS mixins, paired with single-file components à la Vue or Svelte. Then you can use better names (no need for brevity now), keep the styling separate from the markup (but still paired with it), and have a better experience debugging in the browser.
I agree with most of what you're writing, but in arguing this out with people who seem to be enthusiasts, what I think I've discovered is that while there are existing (hell, longstanding) unbundled technical solutions fully capable of solving the problems Tailwind does... they don't solve the practical problems of channeling a group into a good-enough design system, and in fact many people who've been doing CSS have never actually really used a design system (especially if their experience is solely recent, and definitely if their experience is only incidental in the sense that they're application devs first). And many organizations don't have roles where someone can focus on solving this problem.
Just-add-Tailwind may hit an interesting pit-of-success spot for a lot of people in this position, where TW provides the atoms of the design system to scatter in a just-in-time manner. Sure, not elegantly, but practically.
Personally, I'd prefer to work with people/orgs that don't see this is an optimum, but I might accept it as a situational local optimum.
Tailwind is great if you're a startup, or someone who is a webdev and also has to be the designer. But in a large organization, with a company-wide style book, and a design department, it's not a good fit.
Tailwind works for "I see this control in my head, and I'm going to code like this to make it happen." It's not really a good match for "I see this control from the design department, and I'm going to make it fit into the rest of the site codebase like this."
Let's be honest, there isn't much elegance to the non-Tailwind solutions either. At the end of the day it's text input used by a rendering engine to style layout, it and your customers don't care how it got there.
I don't understand Tailwind either; but I find myself struggling with CSS modules when I need to override a CSS rule of a child from a parent. Like, say, my button should always be green, except in this context I want it to be purple, its font-size larger and its padding a bit different. With CSS modules, the parent component is unaware of the class name of the child component; so it cannot target that. Perhaps this should all be done with CSS variables; but then hell, how many CSS variables should my components expose? and besides, I am not even sure even they will completely solve this.
className={isContext ? ".button--context" : ".button"}
----
alternatively if you want many unrelated base rules that aren't color/padding as a baseline:
.button contains base rules .button--default default color/padding .button--context contextful color/padding
className={`.button ${isContext ? ".button--context" : ".button--default"}`}
I have not personally found the need to use Tailwind because of that.
There's a fundamental argument that inheritance is a mirage and things in large projects become much simpler with composition-based approaches. You don't really need to grok the inheritance chain with Tailwind in the same way you do typical CSS.
For my personal projects I'd continue writing my own CSS... but for teams, I'd go to Tailwind without a second thought.
I don't understand what you mean by this. Literally decades ago would take us back to at least 2001. OOCSS, BEM, etc. were all created after that year. Wouldn't it be correct to say "Doing everything with utility classes and OOCSS / BEM are things we hadn't even started doing literally decades ago."?
Deleted Comment
Deleted Comment
the major stumbling block has been how tailwind is mostly just css translated into its own hard-to-memorize lingo.
For example, say I want to do something basic like "display:flex; justify-content: start".
In tailwind you would type "flex justify-start" instead.
Which doesn't really follow any rules as far as how to get from A to B, so it's just a matter of having to look the magic word up in their docs each time until you memorize. And there are a lot of keywords (many modifiable according to n-dimensional properties) to memorize.
I know there are handy slugs like "w-1/3" that encapsulate a best practice - but I'm a person who'd rather master the underlying mechanics of that best practice and be able to deploy, tweak and debug it myself.
I'm often in a cycle where I am tweaking a complex class with 10-20 properties including flex, transforms, animations, etc. - and having them each be on their own line (and the class being in a separate file along with its parents, siblings and children, frankly) is key for readability to me.
I guess in the end I have come to have enormous respect for CSS as a powerful, mature language and I'm not looking to be buffered from it.
This is the only problem of tailwind, it relies on its own lingo, as all the OOCSS/BEM projects. When you involve semantics, you will always bring these kind of problems.
I covered this problem and I solved it with this approach http://minid.net/2019/04/07/the-css-utilitarian-methodology/
I have it open in a browser tab almost constantly.
Another way of saying this, is that Tailwind adds cognitive overhead.
I wish framework devs would just hyphenate (or even colon-ize) the CSS property names fully like "display-flex justify-content-start". I think Bootstrap does their own pattern like "d-flex", but all that does is require one to visit the docs to view some less common properties. Autocompletion pretty much makes typing these a breeze, and having less opinionated patterns for property names will make it less painful transitioning between frameworks.
One thing to consider is that being a bit more terse in tailwind is good because you effectively end up with media queries, dark mode, hover states etc all placed together.
Autocompletion in your IDE makes this easy (the class names are similar to the CSS attributes, even in your examples, so you can usually guess them) and you use the same classes over and over again so you learn them quick. I barely spent 10 minutes in the Tailwind documentation the first few days because of the VSCode extension.
Twin Macro is a great wrapper library for Tailwind-in-JS with strong IDE support and it autocompletes all my utilities. I barely have to type anything to style everything in my project.
I can even hover over utilities to peek at its raw CSS.
https://marketplace.visualstudio.com/items?itemName=lightyen...
And the keywords all seem to make sense to me? It's "n-dimensional properties" but the dimensions are pretty consistent...
1. It's a step function over CSS units. This is the biggest strength, just standardizing that your design uses padding of 2, 4, 8px, but not 1px, 3px, or 1.23123em :). It provides more steps than you need, but still it's good that the core of Tailwind is a design system with defined unit and color variables.
2. Some of the utility classes are very helpful. Even as someone who likes writing CSS, it's nice to not need to give something a custom classname just because I want to put margin-top on it. class="mt-4", done.
I think the problem is Tailwind goes too far and tries to replace EVERYTHING with a stack of utility classes.
This works okay in extremely componentized web apps. It's a nightmare if your UI isn't highly componentized. I've seen projects where you make a button by copy pasting this ~80 character string of tailwind classes all over the place, and then changing the color names if you need to. Good luck fixing that when the designer decides that we don't want any buttons to have rounded corners anymore.
Personally I think the best parts of Tailwind are captured in Pollen[1], but I do wish it came with a subset of utility classes for colors, font sizes, margin, padding, and text alignment. I think the hard part is defining which subset is the right subset... I doubt you could find strong agreement from a large majority of developers on that.
1. https://www.pollen.style
That app is done wrong. If you are using the same styles to represent a button you should use postcss and do
.myButtonClass { @extend: (80 tailwind classes here) }
For anyone interested, you can find it at: https://brixi.dev/
* No more worrying about naming class selectors. This frees up so much cognitive space. The less you have to worry about naming the better. I used the SUIT CSS naming convention before, which allows a mix, and that just creates friction. You need the same level of abstraction all the way through.
* No more flipping between files. You edit your styles directly in the HTML. You will need to consult the TW docs, of course, but they're easy to navigate.
* Tailwind is more than just inline styles. It provides a nice syntax for targeting breakpoints and little utilities for conveying more abstract styles/stacking rules.
* TailwindUI is a great way to jumpstart a project and looks way better (IMO) than Bootstrap's components.
* JIT is awesome
I'd be remiss if I didn't mention some cons:
* Looking at a bunch of class names in your HTML is at overwhelming at first. It's hard to delineate the structure. Using proper HTML elements, roles, etc. helps.
* You will need to DRY up your repetitive styles by moving things to templates/components. So you still have to name things, but just keep it generic (alert, dropdown, badge, etc)
* Sometimes you'll have to create class selectors when working with web frameworks and JS libs that require a single class selector option.
We'll see if UnoCss takes over.
The one thing I don't like is that the culture around Tailwind seems a lot more proprietary, like you're getting three quarters of a product that you need to buy the rest of, whereas Bootstrap felt like you got everything you could ever need for free.
I'm not sure what you mean by proprietary culture! Based on the fact that I've pretty much never seen anyone talk about it, I would guess (total guess, no real knowledge) that no more than 1% of Tailwind users have paid for Tailwind UI.
[1] https://tailwindui.com/
It's fine that they want to make money but it's very confusing for a new user. Ultimately, they might make more money by dropping the shady links if it's turning away enough new users.
across their site would be a big improvement.Try daisyui as a tailwinds plugin. It comes with the missing components. It also allows you to replace your 80 character style for buttons with btn btn-primary.
As a frontend developer I don’t like Tailwind for several reasons, it brings the styling into the structure. As a frontend developer Tailwind is at a forefront of what I would consider bad practice and encourages a code style which would be a nightmare for me to maintain.
That said. Tailwind seems to be loved be people who are not professional frontend developers. It seems to be just the right tool for people who are not necessarily proficient in CSS. And perhaps people like me (and the dead sibling) need to learn to let go and allow other people to have the tools which makes it easier for them to do the job which they are not experts at. For that reason I understand Tailwind, even though I don’t agree with it.
Show me a site that has CSS Zen garden style replaceable stylesheets that totally overhaul the nature of the site. It's incredibly rare and almost always not worth the effort. What business says "I want to overhaul the styles of my application but change no structure at all. I'd posit it's near 0.
Even if that's your goal, and I'd argue that it shouldn't be, you can still do that with TWCSS and the @apply keyword. You can write your generalized names then apply whatever twcss keywords you want to them separate from your document's structure.
If your overhaul amounts to changing a "theme" you can easily do that with twcss. In fact, that's basically the point.
I am a professional frontend developer and I love it.
Pair your tailwind with styled components and you can finally reach the dream of semantic HTML.
I mean header files are OK, and professional C developers probably love them, but not having header files is kind of great too :)
I have a similar comment elsewhere in the thread but it applies here too, I think: the main drawback of Tailwind is that it's extremely general. I'd imagine a well abstracted, focused, domain-specific set of CSS created by experienced frontend developers will be much better within that domain.
i prefer the later. with styling in structure if i make a change in one place, it effects the one thing i intended it to
with structure in styling, if i change one thing, it may impact many other things, some of which i might not intend to and are sometimes unknowable at the time of the change
Deleted Comment
Dead Comment