Hacker News new | ask | show | jobs
by wwweston 1804 days ago
> I believe CSS' primary weakness is the general inability to define cross-cutting abstractions. I think of the style of an object as a composition of concerns: spacing, position, size, typography, color, decoration, etc.

I see this come up and it's so strange to me; the only thing I can think of is that what people are complaining about is too many ways to define cross-cutting abstractions (variables and mixins / other apply boosters and even css classes themselves) so the imposition of a framework-specific way to do it feels like it relieves a burden.

Similarly, I'd guess that you'd see a lot of overlap between people who'd chosen their own conventions for addressing this in combination with other design systems and people who don't like Tailwind much.

1 comments

> the only thing I can think of is that what people are complaining about is too many ways to define cross-cutting abstraction

I meant exactly what I wrote. The primary axis for styling is applying a set of properties using a selector. The cross-axis abstraction for providing restrictions on what values the properties contain has not been part of the language for the vast majority of its existence.

> variables and mixins / other apply boosters and even css classes themselves

The only options here that are actually CSS are variables (which are relatively new to the language) and utility classes, which work against the general desire for semantic class names and separating structure from presentation. I'm familiar with the proposals for the others but I'm not aware of them being standardized and I know they aren't supported in any browsers.

There are plenty of reasons to not like Tailwind but I expect most people who do like Tailwind aren't coming off a project with an established design system and method for applying it. I have some complaints about Tailwind's choices but it's a fine set of defaults and has enough customization for me to disable or replace the utilities I don't like.

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?

When I talk about cross-cutting I'm very specifically referring to restricting the values of properties to the ones matching the design system at the CSS language level and not the can I arrange the page to be styled level.

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.