Hacker News new | ask | show | jobs
by mcv 33 days ago
I agree. I don't really like Tailwind, nor similar CSS frameworks. The whole idea was to separate styling from HTML, and Tailwind is putting it back into HTML through the backdoor. It's just a way to do styling from your HTML without having to touch the CSS, by inserting styling info in your HTML. That's exactly what we were trying to move away from.
2 comments

I think this assertion is where most of the conflict comes from.

There is a fair amount of people that disagree with the premise that it should be separated in that way (Including me).

I personally like this essay by the author of htmx on the topic

https://htmx.org/essays/locality-of-behaviour/

Also just better composition imo.

Practically I think this means components of scoped css, html, js.

People never seem to have the same complaint about mixing or separating app code and sql in the same way?

> it is important to make the distinction between inlining the implementation of some behaviour and inlining the invocation (or declaration) of some behaviour

tailwind’s biggest problem is that it doesn’t make this distinction well.

In a sense this is a strength because it probably matches the amount of effort most devs/orgs who don’t focus here are willing to put in to the problem; this worse-is-better solution is functional enough especially in settings where component separation has already been adopted. Along with some decent baseline design tokens, it’s enough for people who don’t want to care more, especially if they don’t ever particularly see the consequences of hyperlocalizing implementation.

If your project has someone whose job it is to think through design systems and how they’re expressed via CSS, you can do better. If you don’t, you can do worse.

And personally, I’ve seen a LOT of discussion about separating SQL and app code. There’s a similar tension. Wrapping queries in function calls often means fewer duplicated queries (often painfully verbose) and opportunities for dumb security mistakes, but reduces the expressive variation the raw query language provides, and many systems and devs behind them end up pursuing balance between the two… or outsourcing the decision to an ORM or other data access layer whose tradeoffs also probably have shortcomings but at least they get to worse-is-better stop thinking about it except at particular pain points.

There’s absolutely no tension between locality of behavior and separation of concerns in CSS: you’re putting styles on the elements in the document. The styles are defined elsewhere.

It’s like arguing that all of your source code should go in one big file because one file is less than two files, which means greater localization.

Its arguing that that source code that affects the behaviour of something should be easily discoverable from the point/points its behaviour affects. or alternatively more indirection/obfuscation is worse.

Its not so much about same file, as reducing distance to understanding, whether visually or by some sort of easily traceable path.

Like you would want to init a variable closer to its usage, Or that having a 100 wrapper functions is less understandable than inlining for a single statement, or global mutations are harder to trace then local, and that sometimes its easier to inline a single sql statement then split it out into a different file just because its 2 different languages.

Also, to be clear its possible to write CSS that exhibits less or more LoB. The file thing is more that I don't think HTML, CSS, JS "must" be written as separate files which is what the prevailing best practice used to be, justified as SoC. I just think splitting along the scope/behaviour lines rather than file type is more understandable.

> the behaviour of something should be easily discoverable from the point/points its behaviour affects. or alternatively more indirection/obfuscation is worse.

This is why I'm not that big of a fan of Tailwind and similar frameworks. To me it feels like they introduce yet another language into the mix. It adds all sorts of classes directly to the html, but now I need to understand what all of those mean. If I write my own CSS, I generally just have to look in one place to understand the styling of an element.

I think I feel kind of like that about overuse of annotations in Java. (Simple/obvious ones are fine, but not all are simple and obvious.)

> Its not so much about same file, as reducing distance to understanding, whether visually or by some sort of easily traceable path.

The metaphor remains valid. You can do this all the way down the abstraction stack, back to functions.

I separate those too. Queries get their own file. Sometimes their own framework.
Sorry maybe that wasn’t the best example. It’s not really about separation of files. But how they connect.

In sql your code may be in a seperate file but your app code is still clearly calling the sql. The inlining vs not inlining is just abstraction. You could use a function, or a separate file or not, a different language or not.

But there is a clear single call chain at the points where that behaviour is being applied and a single definition.

With css that’s not necessarily true. There’s a bunch of different rules that may or may not apply.

> With css that’s not necessarily true. There’s a bunch of different rules that may or may not apply.

There's only one algorithm, the cascade. And it's described here[0].

And just like any code you write, try not to write complex selectors. If you're not sure two styles are equal, it's better to write two different rules. And just like styling works in any system, you go from generic (standard html elements) to very specific ones (the link in the hero section of the about page)

[0]: https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Casc...

that’s exactly the part that is anti locality of behaviour.

I don’t want/need cascade. I only care about components and building up from them. And I would rather have it be explicit over implicit and scoped/encapsulated.

Call it composition over cascade.

To be clear I think it’s possible to do this without tailwind. And tailwind has other out of the box features/opinions.

But it works well enough without too much friction.

> that’s exactly the part that is anti locality of behaviour.

It is not. Because it fits the concept of "web pages" as documents and forms (which most web apps are, even if they're trying to pass as desktop applications.

> I don’t want/need cascade. I only care about components and building up from them. And I would rather have it be explicit over implicit and scoped/encapsulated.

And you're very welcome to do what you want. But there's no need to bash cascading as it's a good solution for web pages.

This is the misconception that has caused so many problems over the years, problems that the Tailwind approach solves.

There was never any separation of concerns within the HTML code, the class="" property is in the HTML and that is the styling info. Devs took the idea of separation of concerns of content, presentation, and behavior as separation of technologies: HTML, CSS, and JS, which is not the same. So they tended to think, "oh no, with classes I've got presentation code in my content (HTML) and I need to put it all in my CSS." But HTML is not content, it contains content. And all the separation of concerns is done with how the HTML is written.

For example take this code <h2 class="h2" data-index="0">Bleh!</h2>

That has separation of concerns. The content is Bleh!, the content semantics are h2, the styling is all in the class, and the data-index is used only as a hook for javascript. Violating separation of concerns would involve using those properties for multiple concerns. Particularly the h2 class="h2" part. It looks a bit silly at first glance, particularly if you have a bunch of <h1 class="h1"> and <h3 class="h3">'s in the codebase. But that has proper separation of concerns, and I have many times run into cases where I want an <h1 class="h2"> or <h2 class="h1">, and in those cases, because I have proper separation of concerns, all I have to do is change the actual content layer to whatever is appropriate without worrying about the presentation layer changing because someone put an h2 { font-size: 1.6rem; } in the css.

The only difference between the old-school approach and the Tailwind approach is the API between the HTML file and the CSS. The old-school approach tends toward terrible abstractions because devs are trying to code the presentation for an element while feeling they need to describe the presentation in as few terms as possible, because they think that amount of characters is separation of content. Tailwind takes the approach that the class property is the presentation layer and you can use your words to describe it clearly.

I'd add that what I've seen with the older approach almost always leads to much more co-mingling of concerns (maybe because those devs get so focused on "all style should be in the CSS"). That's when I see things like ul > li { padding: 1rem; }, which is fine until you decide to change it to an ol. Or even .foo > .bar { ... }, which is dependent on the structure of the content.

Yes, Tailwind is ugly as sin but it's effective.

HTML is content because it inflects content with structure and meaning. It may be fair to say it carries less of the semantic weight than the language and other media it marks up, but it’s content at least to the extent that punctuation is, and perhaps more.

I don’t know anyone whose concerns with “presentation” in markup included the presence of classes — the dominant understanding among people I’ve known who care about this is that classes are semantic in the markup with names chosen for that purpose and they have presentation attached in stylesheets.

Tailwind gives up on that separation. There can be some worse-is-better benefits to that, especially for teams that don’t have anyone whose role is to care about this. But the “ugly as sin” is a signal about the shortcomings in the tradeoff.

> the class="" property is in the HTML and that is the styling info

The class attribute (not "property") is in the HTML because it's part of HTML. It's markup. Element classes weren't created either by or for the CSS people when CSS came along. The class attribute predates CSS by years and has no more relation to "styling info" than the id attribute does.

Yes, and that’s what it’s used for now due to the ad hoc development of HTML and CSS.
What?
I think I can make what I wrote above a little clearer by putting it this way. When the class property gets really long, that's not a violation of separation of concerns, because you are not really co-mingling content with presentation. HTML is not content but contains content.