My first impression of tailwind was ๐คฎ, css in html, not this again. What about separation of concerns! When I looked at examples they just looked l...
For further actions, you may consider blocking this person and/or reporting abuse
Thanks for sharing your experience! That's one of the few pro-tailwind posts obviously written by someone who actually knows CSS. Helpful to mention the specificity vs. order issue. I have been using XSLT where you must never assume a specific execution order, forcing developers to write descriptive code ready to be split for parallel execution. But many developers are used to imperative code, even those who claim to follow a functional, object-oriented or whatever superior coding paradigm.
The only advantages that tailwind had in my opinion were both related to collaboration in a team. Even with people willing and able to write clean and modular styles, it's easy to make an unpredictable mess of possible side effects in vanilla CSS. And if there are team members who can't or don't care to code CSS properly, or who advocate to put CSS in JavaScript strings in their styled components, I'd rather have everybody use functional class names in their HTML / JSX. Using JS to style a UI feels like giving up most of CSS' advantages for no good reason.
Inconsistent naming and tooling: vanilla CSS is full of inconsistencies and so is every language that exceeds a strictly crafted domain context. And even then, projects tend to become inconsistent. Vanilla CSS, SCSS, and PostCSS have good stylelint support, but I'm not completely happy about stylelint's recommended rules and its false positives and negatives.
Vanilla custom properties (CSS variables) have some limitations independent of the frameworks that uses them, and gradients have had a very tricky syntax from the start. If that's your greatest issue when extending tailwind, you're a lucky dev!
I use tailwind on a couple of work projects and a couple of pet astro/next projects.
I do this because (for work) it's a requirement and (for pet projects) it's helping me learn.
I've been doing this for over a year, yet I remain steadfast: Tailwind is a blight on the developer landscape. Nothing it does could not be done better without utility classes and div soup!
I'm curious as to how you do your css that you find it better. How do you manage components with lots of complex state, etc?
I still "title" divs usually because otherwise it's hard to find things.
Wherever I have a choice, I don't use styles as part of the component. Coupling styles with components means if I do something like move a component from one area of the site to a sidebar or something, then I have to update that component, whereas if I styled the semantic elements correctly in the first place, I wouldn't need to.
For instance, if an
h2
in the sidebar looks like such-and-such, then that's how I want it to look regardless of what component it's in.Why would I want to duplicate styles for every component? Or to update every single template if we wanted to make a change for holiday branding or something?
Sorry, I'm a bit confused, but I think you're saying you style all the base elements in one place correct, like styling all buttons, a, h1, h2, etc? And then you just don't style components (as in groups of those base elements)? Not sure how exactly the last would work, or do you just do basic layout styling?
I still do some base styles depending on the project (like the h2 example you mention), but when I talk about complex components with many states, I'm talking about wrappers around base elements, Like a button, with all the hover/disabled/error/etc states, can be a surprisingly complex amount of css.
I don't have this duplicate style issue you mention, if I find myself copy pasting the exact tailwind classes too much, I either convert it to a utility class for that project, or create a component... This is quite rare though, as I find usually I want a similar style to something I already wrote, but not exactly the same. But if I do have a component and I need a version to look different, I can just pass down tailwind classes that will override the base styles quite easily.
If you convert the same bunch of styles to their own utility class, you're doing CSS, and Tailwind has no benefit at that point. At a stretch, you could say it's because of mixins, but Sass has done those for many years without requiring you to pollute the HTML.
I'm not sure what you mean avout needing wrappers and lots of different states. Semantically, we already have attributes for active and inactive states, and CSS already includes pseudoelements and hover and focus states. Tailwind is reinventing the wheel here.
I don't have a lot of utility classes, I only do very few, like the base styling, but I might not want ALL x (let's say links) styled like the base, so I like having a base link utility class I can add/remove. Otherwise yes, using tailwind just with apply is pointless.
Regarding wrappers, like I mentioned in the post, I switched my component library to tailwind, so for example, I have a vue component for a button. It needs base styles (hover, focus, disabled, etc) and more state styles (primary, secondary, error, etc), AND dark mode styles.
That is a lot of styles that must all be written in the right order with the right specificity. CSS makes this very hard because if I add .primary or data-primary to indicate an additional state, when I use that selector chained with others it increases specificity. Maybe I should have clarified more but the specificity problem applies to CSS way more, but unlike tailwind, there's no escaping it. Also I used Sass before this and even with mixins, etc, it was a mess because at the end of the day a selector needs to be written.
I used to think the same about html pollution, but I can't deny the code I get (see example at the end) is much more readable, maintainable, and shorter to me. I'm always open to better solutions, but one hasn't come along yet.
Great article Alan!
my 2 cents, i find
classnames
(utility micro package) super useful for these kind of statements:the
boolean && modifier
and theboolean ? a : b
are easier to read IMOI mentioned this in the tailwind-merge part which is what I use to do this.
Having a quick look at the library, I would unfortunately strongly recommend NOT using it because it only merges via exact property name. So if you do
c("border-white", "border-transparent")
you will get both borders and the end result is up to the order of the tailwind style-sheet which you cannot control.Tailwind-merge (there are other alternatives if you like) will merge according to tailwind properties. So the example would become
border-transparent
since the last will win. This allows easy correct overriding of styles, especially in regards to padding and related utility classes.I disagree im afraid. The utility I do want is to merge class names with no further logic. Keep which rules apply depending on others to the programmer โฆ well to the client really XD but I prefer this package to care to syntactic sugar , nothing else
Ah, okay, so long as you're aware and it works for you.
I really enjoy writing CSS styles and tailwind taking it away from me. So - no. xd