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?
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.
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...
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.
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.
With the rest I don't really strongly disagree. I think its just a question of complexity. For simple things its fine, but for complex apps with teams of people :shrug:
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 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 metaphor remains valid. You can do this all the way down the abstraction stack, back to functions.
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.)
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 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.
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.
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.