| Possibly I'm not understanding what you're getting at, so maybe it's worth another round of exchange. > The only options here that are actually CSS are variables (which are relatively new to the language) and utility classes So before widespread adoption of SASS/LESS, I might have expected some places that took a systematic approach to design to use utility classes as kind of a mid-tier in a three-layer model that took care of balancing general, cross-cutting, and specific concerns: - general (or very widely cross-cutting) concerns would go at high levels: *, html, body, sometimes qualified with semantic classes for varying pages (e.g. body.departmentname, html.sitesection). A lot of type/line related information would go here, probably some page level margin/padding/alignment and a few other instructions. Then there'd be some kind of generalizations for other tag-level elements (ul, p, table, h1-6, etc). - modestly cross-cutting concerns would get their own utility class names, roughly grouped by categories you're talking about (spacing, position, size, typography, color, decoration, etc), so you'd see .box-I, .type-IV, .col-X, .scheme-C - specific/exceptional "last mile" scoped concerns would get semantic class names (also usually used for attaching behavior via JS). The rise of SASS/LESS seemed to change one major thing: a lot of the middle/modest layer of cross-cutting concerns could/would find their way into mixins and then get imported into semantic class names, keeping the concerns centralized while cutting down on utility class name clutter in the markup. Some shops would use variables instead. Either way, it streamlined the already existing manner of handling the middle layer of cross-cutting concerns. Now, mixins/@apply aren't part of native CSS yet (and though variables are, they're are probably inferior from a DRY/structural perspective), but existing preprocessors have had such widespread adoption for most of the last decade that it's confusing to me for someone to approach Tailwind as if isolating cross-cutting concerns weren't a problem solved in other ways previously. Certainly Tailwind's @apply isn't native either and I'm not clear on why its utility classes would be inherently superior to other pre-existing utility practices. Hence my assumption that most of Tailwind's fans are people who hadn't found themselves working with these concepts before they picked it up. And if Tailwind is people's introduction to working that way -- and it was that hard to come by beforehand -- maybe if nothing else it is in fact doing people that favor, albeit with the overhead of being married to a level of utility classes that I think is simultaneously too scattered and duplicative and its own specific tooling. Or maybe there's something else I don't understand about it yet? |
I haven't explained my biases. Perhaps a technicality but I don't consider the reset styles to really be a consideration. They're something set up at the start of a project and not really touched day to day. With the rise of component-based development, I strongly prefer my styling to not be context dependent and so I avoid relying on styles cascading from outside the component aside from the reset styles. Neither of these is required but I think this is relatively common. This leaves the utility/mixin layer in your taxonomy and thus my focus on it.
> existing preprocessors have had such widespread adoption for most of the last decade
I'd mentioned using Sass mixins as my workaround in my initial post. The compile-to-CSS languages have solved the problem but that doesn't mean it's not a weakness in CSS itself.
Despite having the tools to solve the problem, I'm quite confident very few people have. Virtually all Sass/Less use I've encountered outside the Sass online community has been nested selectors and variables.
> most of Tailwind's fans are people who hadn't found themselves working with these concepts before they picked it up.
Yes, this is the primary advantage for most. Most developers do not have a design system let alone come up with the idea to design something to enforce it. I had to derive mine from Bringhurst's Elements of Typographic style, adapt it to every designer I worked with (they're generally familiar with the overall concept, it just doesn't make it to the popular frontend body of knowledge) and then sell the approach to every team I worked with. I ran into utility CSS much later and then only in online articles until Tailwind.
Since you're familiar with the concepts, you won't encounter a lot of new material here but might find some of the details interesting (I mention some specifics below).
> Or maybe there's something else I don't understand about it yet?
Tailwind's scattered/duplicative nature is a good match for people with the biases matching my own. It's largely competing with inline styles, CSS-in-JS, or scoped CSS. The redundancy of setting styles without relying on the cascade is a feature for component-focused uses where they're desired to stand alone for use in multiple places. The comprehensive (i.e. scattered) nature of the utilities allows for a nothing-but-utilities approach. This avoids class name conflicts and specificity issues, which competing approaches were specifically created to address. Psychologically it also keeps people focused on finding utilities (and thus staying in the design system) instead of hacking in their own CSS.
There's less duplication than I thought at first. Recommended coding style uses component-local cascade for things like font or text color and parent shortcut utilities like space, divide, and gap cut down on the really painful duplication.
I do think Tailwind takes their utilities too far. I think the transition/animation, gradient, and transform utilities are ridiculous even if I do respect the effort. Going the other way, the layout options are underwhelming (grid is anemic) and there really isn't anything around handling images. I consider these relatively minor, nit-picking concerns and simply define custom utilities has solved all the issues I've had here.
In my mind, the more substantive argument against it is an only-utility approach completely tramples on the idea of separating markup from presentation. This leads to a lot of edits and workarounds when trying to use a single component in multiple design contexts, which is a general problem for the component-local approaches. Straightforward css-var things like color are easily handled by making custom utilities with css vars in them. There's also a straightforward general solution in the form of @apply in a named class.
Tailwind is gaining popularity because it's a pretty good fit for the space. My current project is my first professional one on Tailwind but I expect to be using it over my own system going forward simply because it largely does the same thing and is an easier sell.