Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Tailwind and the Beauty of Ugly Code (boot-and-shoe.vercel.app)
80 points by sebg on July 7, 2023 | hide | past | favorite | 119 comments


As someone who is skeptical about Tailwind because I've learnt to separate the structure from the presentation (the old school way).

It reads like the advantages listed in the article would apply if one used style="...." everywhere. Which does not sell it well to me. Then again the author says they needed to actually try Tailwind for it to "click". But then again, they are praising something without much long term insight, I'd be interested to have an opinion from someone who has maintained a project for one or two years, or more.

Tailwind feels like Bootstrap to me: as someone who has written raw CSS for years, you need to learn a new vocabulary and map it to standard CSS. Which I don't feel the need for. I know CSS, and you kind of have to anyway even when using a CSS framework. With the extra disadvantage that you need to have a build pass so Tailwind can pick up the dynamic classes you used to build the corresponding CSS for you. But I really want to write this CSS myself and have meaningful class names, I feel like it helps me understand what's what when working on the structure. I can always inspect with the web developer tools if I want do understand what styles apply.

I see the appeal of having some default design system applied to your thing and not having to write some style reset stuff when using a CSS framework like Bootstrap, but even for this I'm not sure about the benefit/drawback ratio. I work for a company whose product is somewhat trapped in an old version of bootstrap because it can be augmented with extensions, and not the old bootstrap version is part of the API, if you update it you break the API.

I don't know.


Here's a thought: HTML does not separate structure, or content, from presentation. I'm not sure where the myth of the web's separation of concerns first arose - possibly from some architecture astronaut who'd never written an element in their life, perhaps from someone who really knew better but needed to slip something past the mediocrity police - but irrespective of what any non-normative reference may say, HTML does in practice blend structure, semantics, content, and presentation. CSS and JS substantially augment the presentation and semantics, but fighting against the grain of what HTML fundamentally embodies, instead of leaning on the framework, is a prime recipe for technical debt, not to mention opening the door for an awful lot of NIH.

Tailwind responds to that with an organising principle of styles refactored at the abstraction level of page components. It is not supplying an off-the-shelf design system for front-end novices a la bootstrap/material design. That is an excellent fit for a template-driven world, which is to say, most applications of scale. It is also an excellent fit for anyone (or any HTML generation language) that thinks of data as functional and anonymous. Naming things is hard, so the fewer things we're forced to name the better. My CSS has even improved from using Tailwind, not just thanks to the excellent docs but because it's been easy to experiment with alternative compositions.

To your specific inquiry - I've been maintaining several Tailwind frontends for a few years now, and it's been more reusable, more composable, and more maintainable that any of the hand-crafted CSS I might've written in the past, no matter how polished and proud I was of it.


I'm not sure where the myth of the web's separation of concerns first arose - possibly from some architecture astronaut who'd never written an element in their life, perhaps from someone who really knew better but needed to slip something past the mediocrity police

I'm pretty sure it came from CSS Zen Garden (http://www.csszengarden.com). The same HTML with dozens of different presentations all done exclusively with CSS changes. Don't get me wrong, I agree with you that for the most part the separation is a myth, but I personally remember before seeing CSS Zen Garden, the idea wasn't as common.


It's hard to argue against the power of separating content from presentation when we can see the results with our own eyes in a couple clicks on Zen Garden. I have a hard time seeing how the disparaging title of "architecture astronaut" is warranted by it.


HTML and CSS has overlapping control over many properties on how a given document is rendered, so Zen Garden is more like “check out this Turing complete program written in CSS” — cute and interesting, but it is not practical as we can see from.. literally no real website doing anything remotely like that. This myth came from a time when we had markdown-level HTML markups, and it made sense back then: sure, why not let me color headers red? But it doesn’t scale as it simply doesn’t compose. That cascading part doesn’t make sense for many properties: should padding be inherited? It basically never makes sense. Components are the sane building blocks (as has been realized by desktop GUIs decades ago), and we are much better off with strong encapsulation here (shadow dom is a welcome change).


That power is only for the contrived example of doing a complete redesign that doesn’t change any of the html content. It’s like one of those demos people make of a CSS-only thingamajig that would be much easier to do any other technology. It makes for an interesting tech demo but isn’t practical for day-to-day development.


Templates, themeable products like WordPress, dark modes and alt accessibility presentations...


>That power is only for the contrived example of doing a complete redesign that doesn’t change any of the html content.

Didn't Github just re-style their whole UI? Presuming that's an extreme possibility seems like premature optimization unless you run Product.


That’s more like YAGNI.

The other comment made a good point about WP templates, I can only speak to my own experience. I have mostly worked on projects where I could edit the HTML, and in those cases using a Tailwind-like methodology was dramatically easier. Even when doing a full-site redesign.

So if you are designing for a project where you are unable to edit HTML, sure, use the right tools for the right. Or if the bulk of your coding time is spent doing full site redesigns instead of updates to an existing design, then it wouldn’t be the right approach. I wouldn’t use it on a project intended to be white-labelled, otherwise that’s the methodology I’d use.


I think the idea comes directly from timbl himself. Maybe he even got it from one of it the webs predecessors, like project Xanadu maybe. Certainly older than CSS Zen Garden (which is a brilliant project) and even older than CSS (which was the one of at least two style sheet languages that won).

The original idea was that the server provides the content and the consumer (browser) is responsible for presentation. In this thinking the separation of content and presentation makes total sense and the delineation is just a matter of practicality.

If the same party provides content and the presentation I find the distinction much harder to justify. Especially since there is no hard boundary (server pure content, consumer pure style) people will draw the line where it is convenient for them. What you inevitably will end up with is crossovers like in Tailwind.


That would make sense only in an alternative universe where HTML itself didn’t end up with styling-related functionality, but remained closer to its XML ancestry.


HTML was spawned from SGML and HTML predates XML. The only XML ancestry was later on when a couple of versions of HTML were rewritten to be based on XML (XHTML which was eventually abandoned), but even then it needed a lot of backwards compatible escape hatches, and was only valid XML with strict modes etc.


If HTML were specifically about structure instead of presentation, stuff like line-height or text-transform (which carry an obvious semantic value) would've been tags rather than CSS properties.

HTML+CSS(+SVG+JS+Web Workers+etc...) is not a formally correct framework, and personally I can appreciate what Tailwind can achieve even if strays a bit further from an ideal approach.


‘architect astronaut’ is a great phrase.


My take on this is that meaningful class names are massively helpful for maintainability and any kind of development lifecycle.

What is the name of the sub-widget you are currently building? Say you're building a card - if there is a row that has various icons for the features of the thing depicted in the card, alongside a subtitle, what is that row? It's not just an icon row, because of that subtitle. Should it be its own component? Or will you just give it a reasonable name, keep it defined inline in the larger card's component, but make it clear that you see it as a definable sub-layer? A class name is easier and less disruptive to type than creating an entire new React file for a subcomponent.

What about code review and QA? Must the reviewer read a dense string of Tailwind class names just to try to intuit what is going on? And then, when someone doing QA says "we need to add some padding on the..." - can they go into dev tools and see a reasonable name for that subcomponent? Or would they need to refer to it as the thing around the X and Y and Z, because that's the only way they have to describe the thing?

Not to mention userscripts and extensibility. For the same reasons that one might open-source parts of their stack, and for the same reason that app stores drive stickiness, allowing your users to hack on the visualization of your product can be highly synergistic. Using opaque class names takes this power away.

We've all seen Figma files with unnamed Group 142 nested in Group 134 nested in... if they are grouped at all, that is! A tradeoff was made for design speed vs. maintainability/future component extraction. Often that's the right choice at the design stage. But if you work in a realm of text editors and textual code reviews, that may not be the right choice for you.


Unfortunately like “jQuery developers” a decade ago, we now have “react developers” that don’t understand CSS and add more divs until they get the result they want.

A modal log in screen is five elements: a shade, a dialog, two labels, two inputs and a button. These are all very easy to name.

Not 300 unnamed divs. The react developer adds divs and then considers it difficult to name them all.


> A modal log in screen is five elements: a shade, a dialog, two labels, two inputs and a button. These are all very easy to name.

Agreed. But why name them at all if the structure is so simple? Keep your simple, understandable structure, colocate your styles with tailwind classes, and avoid the unnecessary cognitive overhead of naming obvious things (is it .username or .user-name?) and linking them with remote styles in a different file.

Not saying it’s the “one true way”, but I don’t think your way is necessarily simpler.


Unnamed would be great if it was just inline styles. Just not 34 class names per element in a custom DSL plus other rules to get around DSL limitations, plus additional wrapper divs because the developer does not know CSS, which is my experience of tailwind projects (including one from YC).


With all due respect, I think many of us has been massively burnt by that “meaningful classname”, that happened to be also a meaningful classname in a different part of the code, or was not specific enough, or an update to a CSS dependency broke the whole thing.


Tailwind makes a lot more sense when used in conjunction with a component library.


I have used it for three years at this point. I would feel very disabled if not allowed to use it on the next project.

You say that you want to write "meaningful class names", which is something that clicked for me: naming things is hard[1]!

I remember having the feeling that every time I used inline styles, I was cheating in both senses of the word: doing something not allowed and getting away with something too easily. I get that second feeling when using Tailwind.

[1] https://medium.com/p/9eab459633d2


How is naming things hard?

I am looking at a comment, it contains two voting buttons, and some text.

The elements should be : .comment, button.upvote, button.downvote, .text

If you have more elements than that you’re either doing something extraordinary or you need to learn CSS better.


Now do a card-widget. HTML is too barebones to operate without random helper divs, and those can’t be meaningfully named.


I do card widgets all the time without wrapper hacks. So do most competent from end developers. Challenge me on any design you want.


> naming things is hard

This is an argument that would have held more weight for me before I started using BEM. Naming your CSS should be exactly as hard as naming your component, and no harder.

Is your React/Vue/Svette component named "GenericButton"? Congrats, that's your class name. Got some markup under it that you need to style and you're worried about name intersections? Don't be; "GenericButton__whatever". You never need to worry about collisions again, they just don't happen. And you never need to worry about naming, you just use the same names that you're using in your Javascript/Typescript.

----

To me, I look at Tailwind, and it feels like taking a bunch of React components and saying "no, don't separate those out into hooks and helpers, inline all of it." People say that Tailwind is about locality of style, but I just don't see it. Locality of style, component-based CSS -- you do that by using components and by scoping your CSS to those components. You can do that with normal CSS. Heck, there are even libraries that will get rid of the cascade if it becomes a problem.

I'm told that the reason Tailwind often ends up looking like spaghetti code is because you're supposed to be using more helpers with it and that you can make it reusable. Sure, I buy that. I buy that it can be made reusable and composable. But say that you make it reusable and composable -- part of that process is going to be naming things. It's going to be deciding what to name your helpers and your shared styles you want to use everywhere.

So I don't know, maybe there's something I'm missing. I agreed with a lot of the criticisms of "semantic" CSS and I might have been really receptive to Tailwind at some point (I do think using element names in CSS is usually bad practice), but then BEM happened and I realized, "hey, you can just name CSS after the component you have it attached to, and then suddenly all of these problems go away and it becomes way easier to debug because you always know exactly what to search for in the codebase and where to look to adjust every class."

And yeah it's more verbose and the double underscores look a little ugly, but come on, we're comparing it to Tailwind. Having your markup look a little bit ugly obviously isn't a dealbreaker.

I'm trying not to be dismissive of Tailwind in part because a lot of people use it and like it, and I felt dismissive about BEM as well before I started using it. So I keep on using Tailwind when I run into it, I keep on waiting for it to click. It hasn't yet. Maybe I'm just not seeing it or not using it right but I'm never tempted to use it when I don't have to.

----

Edit: I will add to this, you want to talk about coupling CSS to Javascript then one of the cool things about BEM styling is that your generated output documents your Javascript/Typescript.

When I look at an app that's using BEM, and I see part the HTML that I want to change, even if I've never looked at the codebase before in my life I know exactly what to grep to get to the HTML and exactly what file I need to change. If somebody wants something added to a footer, I know what filename to search for to get that footer, I know the full list of every component that's inside that footer just by looking at the HTML. I know how the Javascript code is organized just from the HTML. And that makes it so much easier to just think about individual components without having to worry about understanding an entire application.

In comparison, every time I look at an app with Tailwind, I'm struck by how utterly useless the generated HTML is for doing any kind of debugging -- both debugging style and debugging the HTML/Javascript.

Because it turns out that having every component name in code mirrored to your class list and tied to your styles makes it really easy to cross-reference everything.


There is XSL-FO, less famous cousin of CSS, that formats documents for printing. It has no formatting classes; each element has to have the appropriate attributes. To make it manageable there are, of course, default values and inheritance, so you can set the main font once on the root element and then only use 'font' when you need another. And since these are XML documents and are mostly created via XSL, they can also use an alternative generic mechanism of setting attributes: XSL attribute sets.

I’ve worked with XSL-FO (not as much as I would like to), and I would say that this is a pretty viable approach. First I tried to turn attribute sets into formatting classes (it is totally possible, plus these classes can also form a hierarchy with clear priority rules). This mapped very well to what I knew about CSS and to my experience in desktop publishing. But over time I became perfectly content with just setting attributes on an element directly and only resort to attribute sets when they came naturally as a time-saving technique.

In old times people who wrote about UI emphasised “direct control”: users must feel they are in control of things that are happening on the computer, that they not just convince the computer to do something but can, for example, directly move a file from one place to another. This is an illusion, of course, but the one that gives the interface a very empowering quality. (Which becames more and more scarce nowadays.) As far as I understand Tailwind it gives the same feeling of direct control.


Thank you, this was a good read and positively exhaustive.

Especially the comparison with XSL-FO regarding the cascade: I never felt that tailwind abandoned the C in CSS entirely, it just encourages to limit its usage to a sane and transparent approach (as opposed to specificity wars)


Same here. Have tried a few before moving my portfolio to Sveltekit last year, including Tailwind. And to be honest it does feel Bootstrappy as you said. The simplicity and flexibility you have in some of the functionality of CSS to really do whatever in terms of layouts is fantastic.

The only thing I know for sure, as it's a current problem with the front-end development at work, is that majority of devs are not that experts in CSS and they have hardly spent any time working on raw CSS in their whole career. Which is where I can see the appeal of using Tailwind. Maybe.


I think the appeal of Tailwind is in having the defaults preset (especially if you customise them to your own design needs).

Padding numbers, font sizes, colours available, etc. You're not just randomly picking a px number in a style declaration, or trying to come up with a random variation of red. A new developer can come in and use the standard tailwind classes and they'll be productive right off the bat, regardless of your product's decisions around sizes/colours/etc.

And it scales in a way that Bootstrap doesn't, because Bootstrap imposes a design. Unless you customise the living daylights out of it, it's going to look like Bootstrap. With Tailwind, you're building from scratch, and you can make it look like whatever you want, you don't lose any of the flexibility of CSS.

I, too, had to try it before it clicked; I thought it looked ugly as all hell, tons of random classes sprinkled in. Went against all that we've all been taught in the past (remember when we all worried about semantic class names?).

But it really is useful.


>having the defaults preset

This was very much the appeal to me - it eliminated a ton of different little decisions I would have otherwise had to think hard about, and let me just get into the actual fun part of style.

I also like that most Tailwind classes are named very similarly to the CSS directives that they apply, which meant (for me at least) that learning Tailwind has had a direct impact on my ability to write decent vanilla CSS.

I used it to style my personal site / blog (epiccoleman.com) and was really happy with the results. Previous attempts at rolling my own design did not come out looking nearly as good, so there's definitely something to it.


Man I am right there with you. It just feels like it’s giving up too much. It’s more enjoyable to write the CSS yourself.


The article name describes Tailwind exactly for me.

I personally am a fan of schematic html/css. I remember the days off CSS Zen Garden, with well marked up html you can change the visual look completely by swapping out the style sheet. There’s a nice decoupling layer, it’s flexible, it’s conceptually simple, it works.

Despite all that I find myself using Tailwind. I’m not a frontend/designer expert, Tailwind goes against what I believe makes good HTML, Tailwind is ugly to me, polluting classes with markup. It’s equivalent to the embedding inline styles anti pattern. However in an imperfect world it works surprisingly well for visual styling on large projects, with many teams and components and just as well in small single page sites. The perfectionist in me says it’s horrible, the I can’t be bothered with frontend design in me says it’s so much less effort and avoids styling conflicts from multiple style sheets/components and I don’t care if it’s ugly or against the ethos of good html.


The discomfort is because html and css were misabstracted. They were designed for the old world of documents, where the idea of restyling a bunch of documents for a new letterhead (etc.) makes a lot of sense.

They've been adapted for the world of interface design, but the separation of concerns doesn't make sense in that axis. It makes sense for the content of a document to be separate from it's style. It doesn't make as much sense to separate the structure of an interface from it's style. (In practice they are almost always tightly coupled.)

Tailwind is flattening these back down into roughly one layer from the author's perspective, where they make sense for the design work.

(I wrote a bit more about this perspective in https://t-ravis.com/post/doc/what_color_is_your_markup/)


So what really what we want is to bring back presentation attributes full-force, a la SVG, for contexts where the page is not expected to be printed? Do I have that right?


I don't mean to prescribe anything that specific (lest anyone reject the diagnosis because they don't like the prescription).

I think people are using Tailwind in roughly a presentation-attribute way in order to claw back some of the combinatorial complexity that comes from letting conceptually-distinct components share a namespace.

I don't mean that stylesheets are a bad/wrong way to express style for interfaces, nor that we don't want a separate DSL for expressing style. Web components are a meaningful gesture at better ways to manage the problem, but you still need a decent chunk of JS to take advantage.

(If you must, imagining how native HTML + CSS could support expressing components with well-controlled encapsulation/boundaries might give you a better sense of where I'd try to start if this was suddenly my problem to solve.)


I would strongly disagree with this, for two reasons.

1. Interfaces aren't special, the majority of application interfaces on my computer are just interactive documents, they're just styled to look like they're not. Outside of some specific examples (games, Blender, Krita, maps), I think very often if you can't sit down and describe an interface as pure text, something has gone wrong with your UX. And in fact, if you're interested in building genuinely accessible apps for low-vision users, it is a prerequisite that you be able to describe your interface using just text.

Most native apps are just interactive documents and forms.

2. The need to change presentation depending on context has gone up over time, not down. There's this theory that documents used to need to be flexible, but now we're all using interfaces where the data we're displaying should be tightly coupled to the interface and it just doesn't make sense given that screen sizes are far more diverse today (HDPI scaling is still a problem on Linux), phone sizes are more diverse, we have people using apps in hands-free settings, they're getting tied into personal assistants, we have more awareness now of accessibility concerns, devices like the Steam Deck exist.

Building polymorphic interfaces is more important today than it was 20 years ago when you could make 3 interfaces and just call it a day and assume you were supporting every device/control scheme. You didn't have people asking whether they could control your reader app with a gamecube controller.

And there are only two ways to build good polymorphic interfaces -- redesign multiple versions of the same interface, which doesn't scale and is guaranteed to leave uncommon and under-represented devices behind, or dive really hard into semantic[0] interfaces where you describe more precisely what data is rather than just what things look like.

The tight coupling of interfaces to presentation is usually bad for the end user and is usually unnecessary (in my opinion, based on the native desktop applications I commonly use). I often think that user interfaces would improve dramatically for everyone and our interfaces would be a lot easier to adapt to new computing interfaces and control schemes if we forced developers to build them with their monitors turned off, and then handed off the finished project to a separate team to make them look pretty.

----

I do agree with you on one point though:

> HTML wasn't designed for my ~modern assumption about what the document is. It was designed to be the document

HTML is at its best when it is not treated as a way to author interfaces, but rather as a render target in and of itself. A lot of design problems on the web stem from the fact that app developers view the pixels on the screen as their primary UX rather than as a secondary side-effect of their UX, which is HTML.

And I guess also to be fair, there is a valid critique here about the HTML "color" representing a mix of concerns. In some ways, HTML is kind of a flawed example of what we're trying to do. HTML was one iteration towards this idea of having user-facing data-driven interfaces. It's not necessarily perfect, it's just that it hasn't been supplanted (yet).

[0]: I understand you don't like the word (https://t-ravis.com/post/doc/semantic_the_8_letter_s-word/), but it's the best one to use here.


I think you would be strongly disagreeing with something I didn't say.

> Interfaces aren't special... if you can't sit down and describe an interface as pure text, something has gone wrong with your UX.

I'm not sure how this disagrees with anything I wrote. I am not even saying that defining an interface with xml is bad. I'm saying the interface of a website and the documents it contains are muddled.

> There's this theory that documents used to need to be flexible, but now we're all using interfaces where the data we're displaying should be tightly coupled to the interface and it just doesn't make sense given that screen sizes are far more diverse today (HDPI scaling is still a problem on Linux), phone sizes are more diverse, we have people using apps in hands-free settings, they're getting tied into personal assistants, we have more awareness now of accessibility concerns, devices like the Steam Deck exist.

I said literally nothing about tossing aside responsive/adaptive interfaces or designs.

I said that interface-html and interface-css are tightly coupled. This is already true. They already almost always evolve together. It is already exceedingly rare to see a web site/app fully redesign without changing html.

I don't think we're in disagreement.

I am talking about the document and interface's style and structure being entwined together because the tools were designed for something different than what they are mostly used for. I am saying component-oriented approaches are ~recognizing and trying to rectify this mismatch (and people using Tailwind are reacting to a real deficiency in the core technologies).


Apologies for reading more into your article than it was trying to say. You're probably right that we're talking past each other a little bit. That being said:

> I'm saying the interface of a website and the documents it contains are muddled.

There is some truth to this, but it's overstated. I don't believe that the distinction between a website and a document is particularly clear on a conceptual level. Those things are muddled on the web because they are actually muddled in real life, there isn't a clear distinction between a document and an application -- and often it makes sense to treat them as the same thing.

> I said that interface-html and interface-css are tightly coupled. This is already true. They already almost always evolve together. It is already exceedingly rare to see a web site/app fully redesign without changing html.

I don't think this is particularly strong evidence either. Redesigns are large. I'd say an above-average number of site redesigns that I see involve changing the database layer too, that doesn't mean I'd encourage everyone to stop separating their database from their application logic.

A bigger thing here though is that this feels opposite to me to how I think about HTML. HTML in your app should be more likely to change than your CSS, not the other way around. HTML is your user interface. When you do a site redesign, you change what data you present to the user and how you present it. That's HTML. To me, this is like saying that splitting font display from UTF-8 characters is wrong because most of the time you revise a book it involves changing the characters, not just the font.

Incidentally if you redesign a website you will also often change the style, but... the style is secondary. I love the CSS garden stuff, I love how it got people thinking about separation of concerns, but it also encouraged people to think of HTML as if it's this extremely static interface that we apply a manifold of styles to, and that's usually incorrect.

So sure, of course HTML and CSS often change in parallel, but... so?

----

> I am saying component-oriented approaches are ~recognizing and trying to rectify this mismatch (and people using Tailwind are reacting to a real deficiency in the core technologies).

This is another thing where I feel like there must be something I'm missing because if you said this in isolation without mentioning Tailwind, I think I'd agree with it. I do agree that using semantic tags in CSS is bad for maintainability. I do agree that CSS has downsides, and I do think it should almost always be used in a component-oriented fashion.

But I've used Tailwind for a little while now (maybe not heavily enough, I don't know?) -- I don't think Tailwind is very component-oriented. It's component-oriented in the strictest sense that you put styles on a component. But it doesn't encourage building logical units of style, it doesn't encourage reuse, it doesn't encourage structuring of style, it makes it harder to look at the output and understand where a style is coming from or what part of the code set it.

You can have that stuff with Tailwind, but Tailwind doesn't seem to be helping with it, and most of the time that I see Tailwind it makes it harder to reason about the style of the app in a structured way. Most of the time I see Tailwind it's just attached directly to HTML like an inline style. And if I came to you and said I was going to stop using functions and just inline all of my code, you wouldn't characterize that as "component-based programming".

Honestly, if we're talking about component-based interfaces, Tailwind-based interfaces feel a lot more like early JQuery interfaces than they feel like React or Vue. Forget separation of style and layout, I don't think Tailwind encourages the use of components at all.

At least to me -- again, I know a bunch of people love it, I keep thinking there must be something I'm missing. But in practice, every Tailwind app I hack on makes it harder for me to couple CSS to a JS component.


> Apologies for reading more into your article than it was trying to say.

<3 (Nothing wrong with reading in, but thanks nonetheless.)

> You're probably right that we're talking past each other ... I don't believe that the distinction between a website and a document is particularly clear on a conceptual level. Those things are muddled on the web because they are actually muddled in real life, there isn't a clear distinction between a document and an application -- and often it makes sense to treat them as the same thing.

Part of the trouble here is that document is an overloaded term (there's a reason why the linked post has a full section on what is and isn't the document). You may be disagreeing with where I'm choosing to draw the lines here, and that's... okay. I suspect this is mostly coming down to perspective.

Categorizing isn't my natural mode. The world is a mess of gray, and a single language closing over both interfaces and documents is necessarily so.

(At the risk of projecting...) I get the sense you're seeing this from something like the context of what I called the "html-concrete document". From that perspective it's mostly unclear what bits are an interface and what bits are documents (and whether there's one document or N of them, etc.). They're all already muddled in the concrete document. (If you step up to considering several html-concrete documents on the same site, I guess you could use template induction to work towards understanding.)

The perspective I'm coming at this from is concerned with how we can author marked-up documents to maximize reusability. This perspective is concerned with, as the post said, "the one closest to the document in the eyes of the author" which I called "an abstract-document". I think this is conceptually clear (but it may not be clear to anyone but the author).

> So sure, of course HTML and CSS often change in parallel, but... so?

I didn't say it was a problem that they change in parallel--just that this change is a sign that the interface-html and interface-css are already tightly coupled. I'm not arguing for more or less coupling between them, but pointing out that a fraction of the global html/css/js namespaces are comprised of tightly-coupled code structure/style/behavior that comprise "the interface" (as the interface designer sees it) almost certainly co-mingled with structure/style/behavior for stuff that isn't the interface (where they can all unintentionally clash).

> This is another thing where I feel like there must be something I'm missing because if you said this in isolation without mentioning Tailwind, I think I'd agree with it.

These are separate ideas (hence the aside). I'm not arguing that Tailwind is component oriented. The component folks, and the Tailwind folks, and the BEM folks (and many more folks trying different things!) are all reacting to problems caused by the status quo separation of concerns. The component folks are more directly trying to rectify the mismatch, but they're all still patching around deficiencies in the stack.

> I've used Tailwind for a little while now (maybe not heavily enough, I don't know?) -- I don't think Tailwind is very component-oriented. It's component-oriented in the strictest sense that you put styles on a component. But it doesn't encourage building logical units of style, it doesn't encourage reuse, it doesn't encourage structuring of style, it makes it harder to look at the output and understand where a style is coming from or what part of the code set it.

I could probably clarify that I find the Tailwind style a bit revolting, and set about writing the linked piece in part to dunk on it (among others). In the process of pulling things apart to understand them, though, I felt like I could see the problems it's reacting against. It's a ~reasonable way to make lemonade, even if I don't like it.

> Most of the time I see Tailwind it's just attached directly to HTML like an inline style.

This is both a thing I personally find revolting about Tailwind, and a big part of the value/leverage I think Tailwind users are reaching for.

> And if I came to you and said I was going to stop using functions and just inline all of my code, you wouldn't characterize that as "component-based programming".

Maybe reframing this function/inline analogy a bit will help clarify?

If you showed me a 2000-line function, I'd ask the obvious question about why you didn't abstract it out into multiple units with meaningful names.

But if you responded by explaining that this code was destined for a global namespace where there was a real risk of code written by others also defining/overwriting/wrapping the identifiers you chose, we'd end up having a similar conversation about the ways around. You could hand-namespace all of the identifiers and make human reviewers keep up. You could introduce tooling to namespace identifiers to avoid clashes. You could try to engineer in stronger component boundaries. You could indeed choose to inline as much as possible.

I would say I'm not a huge fan of the inlining approach because it's a mess to read, but if you countered that you were extremely confident that the code was stuffed with implementation quirks so tightly coupled to something in the stack that it would almost certainly not be reusable elsewhere and would almost certainly be faster to rewrite from scratch than understand and refactor... I wouldn't call you crazy.


Thank you for this discussion and article, both were an interesting read!

One tiny criticism regarding the article: I was hoping you would actually color code the HTML code samples visually, I believe it would have aided understanding better. You could have even used a more realistic/concrete sample as well.


Thanks for the kind words :)

In 2021 I prototyped some documentation single-sourcing tools. I made leaps fueled by intuition and years of frustration, so I found it hard to explain to others what I did and why.

In early 2022 I started sketching this post as ~intellectual-groundwork on the ~motivating problems I saw in existing markup languages. What I hoped would be a few weeks stretched into several months of drafts I wasn't happy with.

Trying to write one _coherent_ motivating post made it clear just how many iterative intuitive leaps I'd made along the way, so I started splitting out asides/sections into posts to make incremental progress and show my math. (The linked post is currently the most-recent of 6 on documentation at https://t-ravis.com/room/doc/; the other 5 have seeds in it.)

Color-coding the examples was indeed on the to-do list from early on, but after starting over a few times and still feeling unsure it would communicate, I got frustrated enough (exacerbated by unrelated ~burnout) to just shove it out the door and turn to other fires for a while. (Part of why I haven't made a follow-up post, even though I intend to.) It's been better received than I feared, so it probably makes sense to go back and improve those when I start the next post in the series.

(You can see where it falls in the rough outline of the broader intellectual project at https://t-ravis.com/post/doc/the_trouble_with_anonymous_gizm...)


I adopted Tailwind but I did it in I think a way that would make the creator of Tailwind crazy. But it’s for a project only I work on, so meh.

I’ve found that even with components that can do their own scoping, it becomes easier to use a semantic class name. Because I’ll create a component, and then later want to use it in a different way I didn’t originally consider. If you don’t have a semantic class name applying overrides becomes difficult.

What I end up doing is designing things in browser, because it’s so quick. And then I slowly abstract it out into a class with @apply rules, but I have my own way that I like to group them. So like one line will be for typography, one will be for layout. It’s so much less verbose than regular CSS I find it really easy to read and change quickly.

But I also know CSS really well, so I can quickly scan the shorthand and understand exactly what it’s doing. Tailwind is the first time I’ve ever willingly used a CSS framework because it just clicks for me, but I don’t use it the way it’s “meant” to be used. Also the defaults for things like text sizing etc… help keep me standardized somewhat. It reduces the number of options and in a good 70% of cases prevents me from spending hours obsessively changing the first or second decimal point of a number and trying to decide if something looks better being 1 pixel to the left (or sometimes a half or quarter pixel )

So if you have OCD, consider Tailwind!


IMHO the secret of tailwind is that it is not really a CSS framework, it is a different way to author CSS.

The only real difference is that you do not use >, +, or *


I think it’s an interesting question - what should the goal of a CSS “framework” be?

Because in the past, CSS struggled with achieving basic common layouts without using hacks. That’s why Bootstrap and its grid system were so popular.

But that’s not an issue anymore. Tailwind doesn’t hide much behind abstractions. So many times as a programmer, I’ve been forced to adopt tooling that promises to make something easier, only to have issues with the tooling, or it having its own learning curve etc… outweigh any benefit.

Tailwind is just easy, and it’s the first time I’ve encountered something that actually rewards underlying knowledge instead of trying to prevent the user from needing it.


There are enough people who advocate for Tailwind that I can't dismiss them in good conscience, but if you put a gun to my head and forced me to give my honest opinion, I can't think of a single problem that Tailwind solves that isn't better solved by web components and scoped CSS, BEM, or a decent CSS-in-JS library.

When I see articles praising Tailwind, they're almost always comparing it to the worst possible way to write CSS -- a mixture of arbitrary classnames that get reused across components and semantic styles that refer directly to HTML and use child selectors to target specific elements.

Well yeah, if you compare Tailwind to that, it probably looks great. If you compare JQuery to building HTML templates in PHP using string concatenation, JQuery probably looks great too.

Again, I can't dismiss it, the people advocating for it must know about these other solutions. I can't dismiss them. But I don't understand it. And the articles that are written about why it's good are entirely unpersuasive. They're talking about problems that I consider to be already solved.

People advertise Tailwind by saying "we want the styles to be based on the component." Yeah, I want that too, but it sure looks Tailwind is a really inconvenient, cumbersome way to do that. You can scope CSS to components if you want to, that's not something that requires Tailwind.


Exactly.

The moment you start working outside of the React bubble you begin to discover just how many of these problems are solved by things like Svelte/Vue's single-file components and a few decent editor extensions.

I don't have to go hunt for a separate CSS file to see what is happening with my semantically named classes. I don't even have to scroll to find it in the same file, I can just option-click the class and see a mini-window showing the relevant styles, edit them inline, or jump to where they are in code. I can find out which classes are unused or where they are used. I get the best of both worlds.

Additionally the moment you get into anything beyond basic layouts the readability of Tailwind drops from "a little frustrating" to "completely opaque". Start adding new CSS features like variables, wide-gamut colors, sub-grid, etc and your neat Tailwind classes start looking like abstract [ ] and letter soup.

Tailwind has some really cool benefits like helping you stick to consistent tokens from your design system and being able to copy paste most HTML from one project to another and have it work, but those benefits simply do not outweigh the downsides I find when I am working in a real project I have to come back to edit and iterate on with multiple people who don't all know CSS well.


> and being able to copy paste most HTML from one project to another and have it work

coughweb componentscough

I don't want to be derisive about it, but... yeah, agreed. I just feel like these are solved problems and Tailwind proponents are acting like it's novel that Tailwind helps with them. My immediate thought on hearing about even the benefits you bring up is that this doesn't seem like a realistic scenario?

One of the stated benefits of Tailwind is that it addresses this concern that the HTML and code/logic and CSS aren't meant to be separated from each other and they interact so much. Well, given how tightly coupled HTML and logic often is, how often does it actually happen where you can copy HTML from one project to another and not have to reformat it from one framework into another -- if you're writing React you're already coupling that HTML to your code. If you're writing Svelte, you're using Svelte templates that won't be present in Vue.

And if you're using CSS-in-JS, or heck, any scoped CSS solution at all then copying over that HTML means copying over the HTML and then... also hitting copy-paste on the block of CSS. That's not exactly a major time save. And even there -- how often am I going to import a block of HTML into a new project and not want to change the CSS to match a new style guide?

There is a solution that allows you to basically import everything without worrying about whether it fits the rest of your application logic and styling though: web components. I don't personally get a ton of use out of them in my own development, but they seem basically decent and they seem like a much better solution if someone is worried about having a shared component library across multiple apps?

---

I can't dismiss that there are developers that I respect who say Tailwind is great. I am not going to say that they're bad at CSS or they're inexperienced or something, that's clearly not the case. But I just wish they could explain what they're getting out of Tailwind in a way that I can understand. "You have to try it to understand it" -- I have tried it, I still don't understand it.

It doesn't help that so many of these arguments start with "imagine not needing to worry about specificity." I haven't worried about CSS specificity in years.


I don't understand why it's an either/or between Tailwind vs using CSS classes. Tailwind is awesome. At the same time, no, repeating the same styles for links, buttons again and again isn't great. Code littered with hundreds of classes is plain ugly and makes it hard to read and work on. This[1] is a valid complaint about Tailwind. The < span > at the end has nearly 20+ classes.

At some point, you should abstract some set of classes. In some cases, CSS selectors and other CSS feature will allow you to do what you want with far fewer lines of code.

[1]: https://twitter.com/xirclebox/status/1673557143088242689


You can quickly create a .primary-button (or whatever) class where you group all the Tailwind classes with an @apply. Then just add primary-button wherever you want.

https://tailwindcss.com/docs/reusing-styles#extracting-class...

I'd also add that the code in the Tailwind example is much easier to maintain and jump in on. It describes everything going on without you having to cross-reference a separate CSS doc with all of the actual meaning hidden in it. Joining a new project with 1000+ line CSS files + media queries randomly added throughout is a horrendous experience.


is @apply a preprocessor thing? does CSS still not have a native way to do multiple inheritance/traits?


You can use CSS preprocessors such as Sass that have inheritance. But most people doing front end design these days separate out design elements into components, which pretty much completely handles the re-usability of the underlying CSS. But @apply is useful for smaller elements used across components like buttons, form elements, headings, etc.


My opinion, here's the deal: no, you don't need to abstract any set of classes. That defeats the purpose. But there's a catch: you must be working in a modern component-based framework to work like this effectively.

Because that's the context where Tailwind grew.

If you have your set of e.g. React components defined you don't really ever "repeat the same styles for links, buttons again and again". You just use your components. <Button/>. <Link/>. <Card/>. <Container/>. Whatever you need. And then your only "raw" tailwind in your "templates" is the scaffolding around it.

And it's great. No write-only CSS syndrome, no coupling between components, at-glance understandability of what's going on.

But you gotta be using components, otherwise it's just overwhelming.


It's an either/or because once you start heading down the Tailwind/Bootstrap path, it pulls you out of the habit of using proper classes and such, and now you have fifty pages where some bit of text uses "text-xl" or whatever instead of a proper and descriptive class. You get into the habit of writing HTML with a bunch of styling directives in it, just like we did in the pre-CSS days.


I do agree, it's easy to abandon classes altogether. It's also a bit concerning that newer devs are starting with Tailwind. At the same time, I think one should be able to notice that certain styling is just getting repeated everywhere and abstracting it out makes sense.

What I actually like about Tailwind is not that you don't have to create classes at all, it's that you don't have to do it for things that don't need it. My old codebase was littered with hundreds of classes doing the same set of styling — padding, margins, flex-box stuff. That's the biggest thing Tailwind helps with.


That may be an issue with inconsistent design elements on your site, then. Simplify, reuse as much as possible, simplify again, repeat.


You are using the word "proper" twice as to indicate that it's well established what that means in terms of CSS. Adam felt that the idea of semantic names wasn't really working. This was an itch that I had myself without ever articulating and I think that the popularity of Tailwind shows that many developers felt/feel like that.


> You are using the word "proper" twice as to indicate that it's well established what that means in terms of CSS.

To say "proper classes" doesn't imply anything about CSS. Classes are a markup concept. The class attribute predates CSS; CSS's selector language lets you target "classified" content, but it's not like classes were invented for CSS.


> it pulls you out of the habit of using proper classes and such

What's "proper classes and such"? You mean hundreds of increasingly specific and non-reusable BEM abominations like `.hero-text__sticky-container--secondary` that no one remembers and creates new ones?


Oh the joys on having to edit a website that was made (by myself or someone else) years ago before Tailwind. It takes at least a few hours to figure out exactly what all these class names actually do, and you are still never sure that there isn't some random lines in the CSS files that will prevent the style from changing like you hoped.


Proper classes would appear rather more like `class="secondary sticky container hero-text"`* in the markup. So no.

* or `hero text`, even (sans hyphen)


Have you ever jumped in on a project with hundreds of "secondary sticky container hero-text" all over the code base? It is a woeful few hours (at least, maybe day or two) of cross-referencing all of these "semantic" class names to their definitions in CSS, and even then you are never truly sure if there is another rule overwriting your changes somewhere else in the CSS. And good luck if more than one developer has touched the code since you last saw it.


As I replied in a sibling comment: https://news.ycombinator.com/item?id=36635382


No, that sounds like a tangental problem born of inexperienced developers and/or poor communication.


> No, that sounds like a tangental problem born of inexperienced developers and/or poor communication.

I've yet to see a single project to not devolve into a mess of class names. Not only that, but a mess of class names with significantly repeating boilerplate, intimately tied to specific elements.


There are many, many, many cases where communication is not possible because who is working on the code now didn't exist when it was written (unless you want to take the time to document out all of your CSS and hope that everyone who touches it follows that documentation exactly). A new team taking over, a new agency updating a website for a client that was made by another agency, a new developer being brought on, etc.


Sure. That's not a problem exclusive to CSS, though, and I don't see how it's one fixed by allowing bad coding practices.


I agree with you somewhat, I wrote a blog post called "Use 98% TailwindCSS, 2% plain CSS"[1]. I have recently been making an effort of making dark/light themes work and the problem increases again: it's a bit too easy to forget a set of qualifiers. I know that a number of libraries attempt to create "smart" class combination functions, so maybe the best solution is somewhere in that direction.

[1]: [link redacted]


It's not a valid complaint.

You extract those into components, and use them as components


Sorry for the rant incoming, but please no, for the love of God, no. Absolutely do not create a new component if it's just to abstract a CSS classe and a few HTML elements (unless you really really use it a lot).

I've been on a project like that, and the result was maddening: any page or component template would contain only references to other components and almost no plain HTML tag.

Each time you encountered something like a 'Title' or a 'Button' or a 'FooBarHeader' component, you didn't knew how much Javascript was executed behind each of those, or wether it had any side effects until you looked at the code (and sometime had nasty surprise on components used everywhere).

You also either had to look at its API or modify it to correctly use the web plateform (eg: how do I specify to my 'Button' is of type="button" or of type="submit" ? How do I add some aria attributes ? What if I want to add a 'data' attribute ?).

On top of that, the generated, runtime DOM would look nothing like the design-time template you are changing, which goes against the plateform, again.

And you also ended up with a huge 'components' surface, where this moderately complex (in term of essential complexity) had more than a hundred components, with some basic 'Button' component being monstruous 500+ lines of code under the hood (because of CSS-in-JS), all of it destroying the performance of the page.

On this particular project, I realized that the tag-to-component ratio was less than 1, even maybe closer to 0 than 1. In other words, behind each little <span> visible in the inspector, you had something like 3 to 5 component instances. I've called it "loosing your footing", as you couldn't touch any primitive, drowning in a sea of abstraction.

Somehow, I feel that it's more specific to the 'React' world which is a bit too trigger happy when it come to creating new component.


Any tool can be wielded incorrectly. You don't need JS to split something into components, components as a concept is orthogonal to JS.

The entire history of CSS is about the struggle to create components: from BEM to Sass and nested CSS. Separation of concerns cuts both ways: https://twitter.com/simonswiss/status/1664736786671869952?s=...


It’s not an either/or within Tailwind itself. It explicitly allows you to add classes like that using the built in styles using @apply (IIRC buttons are the example used in the docs).


The docs actively discourage you from doing this.

https://tailwindcss.com/docs/reusing-styles#avoiding-prematu...


They discourage you from doing this wholesale for the good reasons in the link you posted. But it is still highly useful for small elements that are reused across the site.

Plus, I'd assume that almost everyone using Tailwind is going to break their website/app into reusable components - which negates the need to use @apply across the board.


Clearly there are lots of people who love Tailwind, but for me it really misses the mark.

Yes, it's extremely ugly and unreadable when you have 10-20 classes.

But worse, you have to repeat them in other components even if you only want to change a single one of them. And making changes to multiple components, good luck.

Thanks but no thanks. I'll continue with my systems designed in css and sass.


Tailwind makes a lot of sense for people who are doing componentized UI frameworks where they never write the same markup twice. But if you're actually writing markup in the more "traditional way" where you repeatedly mark semantic elements with classes in order to make them have a certain look and feel (and let CSS do the heavy lifting) then Tailwind is a mess.

In my experience that distinction is the most of the difference between enjoying Tailwind and not.


I don't get the reasoning, you could do the same with Tailwind, just make a mega class with all your "css". Nobody says you can't, although personally I don't do this.

<div className={`${variableWithMultipleTailwindClasses}`} />


I use a vscode extension [1] to fold all CSS classes. Really helps to clean up the ugliness when I'm not focused on styling.

For components, I move the class names to an @apply directive in a css rule

[1] https://marketplace.visualstudio.com/items?itemName=stivo.ta...


You can still use global styles with tailwind. After you style components like buttons, inputs and cards globally, I've found surprisingly low amount of repetition.


I think where a lot of people get hung up on tailwind is they where taught Separation of Concerns. Where are tailwind takes the approach of Locality of Behaviour.

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

A nice essay on this by the creator of htmx.


So basically the web went astray with @media, otherwise we would've had presentation attributes? This is sorta underlines how XHTML would've been so valuable for namespacing layers of behavior like this from one another, satisfying the desire to scope the web authoring experience: namespace for attributes for declarative behavior, a la htmx; CSS where we don't expect to print the page; we already have this for math formulations, SVG; etc


Tailwind is fantastic, changed the whole game for me.

I've built all my projects with Tailwind and I'm never going back to writing all the UI in regular CSS or SASS. CSS is still needed of course, but the 95% Tailwind + 5% CSS rule makes my life easier and happier.


I just have too much love for styled components.

I love naming things, it really helps you think about abstractions and guides you to reusability and more minimal design systems.

It probably depends where you are coming from, my day job generally involves building finicky complex UI's, Tailwind and other frameworks always just get in the way and look fugly by the end of implementation.


Tailwind, htmx, AlpineJS, etc all seem to suggest we took a wrong turn giving up on XHTML, because as it turned out, we actually did want the ability to refer to declarative attributes for distinct sets of browser behavior: styling with no real expectation of handling `@media print` in the case of tailwind (obviously you can but its likely not the dominant use case), IO and composite DOM mutation in the case of htmx and AlpineJS; etc.

Moreover, XML namespacing allowed us to scope the web authoring experience, so that one could fluidly scale from the default case of document layout up to whatever desired levels of interactivity and the semantics to support that, all the while engaging with a minimum of JS. Being able to easily integrate new semantics in an opt-in way could've allow for faster innovation.


I've been playing with reactive data binding via my own library and platform and it's a joy to use (https://book.adama-platform.com/rxhtml/ref.html)


I've been using Tailwind since its release. I think it is fantastic and I'm so grateful for it. We're also happy customers of TailwindUI. I just launched a new product and we could not have gotten to market as quickly without Tailwind.


I've never understood why public opinion is so polarizing on Tailwind.

Could someone with experience in both camps help me understand the tradeoffs, and offer any guidance on whether Tailwind would (not) be a good fit?


The separation of HTML, CSS, and JS doesn't make sense when you're building applications instead of very basic documents. Style, content, and behavior are all intertwined: say you have a collapsible navbar; does the toggle button (HTML) have any meaning at all separate from its behavior (JS); does a "navbar" mean anything at all without its associated style (CSS)? <nav> might have some semantic meaning, but really it's just a div with a list of anchors until you turn it into a navbar with CSS.

Centralizing these nominally separate things that aren't actually separate in modern web applications makes sense. It doesn't have to be Tailwind, but Tailwind works well and is easy enough to understand in a second.

The biggest downsides are that until you get the hang of it you have to look up class names a lot (although they are fairly consistent), it requires knowledge of CSS already so isn't really beginner-friendly, and it can be easy to get lazy and cause a similarly inconsistent and chaotic style soup--am I using px-2 for these kinds of things or px-4--as you might with inline styles (but Tailwind provides nice facilities to avoid this by configuring your theme and adding your own component classes--the latter might be best used sparingly and avoided through better reuse of HTML).

I think most Tailwind users are using it in JS. It works just as well if you're doing everything in HTML, like with htmx or something similar, which is nice for me.


Note that I'm a Tailwind hater.

Tailwind and similar frameworks divorce the concept of a semantic web we as a society have been building towards for decades. It works against the idea that you mark up areas of your code with descriptive labels like "header" and then put the code describing how the header should appear in another easily-editable file, and instead encourages you to use generic style descriptors to describe how the header area of your site should appear in the HTML itself. This is how we built web sites before CSS was widely adopted and, though it was "easier" to do things like `<p color="#999999">` in HTML 3 rather than separate the code from the appearance markup, it was generally considered to be a really bad idea. But Tailwind and the like drag us back in that direction.


> concept of a semantic web we as a society have been building towards for decades

This makes no sense to me. Semantic Web was a mostly failed attempt at making web pages readable to machines. Your actual complaint seems to be Separation of Concerns. Nevertheless, that is something that is only of interest to a subset of developers. Society doesn't care.


How did it fail? Are you speaking just in terms of its slow adoption?


I'm speaking in terms of no adoption.


The person you're responding to wrote about "a semantic web", not the Semantic Web. Ordinary class names, done properly, add semantics to Web pages, and this is what went on for years without Web developers necessarily trying very hard or even knowing that's what they doing—until people started abusing the medium and writing CSS compilers/automanglers and then, later, stuff like Tailwind.

Did developers adopt the ideas? Mostly no. But were they actually still doing it, despite not having bought in to the philosophy? Yes.


> Ordinary class names, done properly, add semantics to Web pages

CSS classes added semantics, really? Assuming that is true, who exactly was this visible to? Definitely not any reasonable definition of society as the GP claimed.


Yes, really.

> CSS classes added semantics

They're not "CSS classes":

> Classes are a markup concept. The class attribute predates CSS; CSS's selector language lets you target "classified" content, but it's not like classes were invented for CSS.

<https://news.ycombinator.com/item?id=36630297>


"No adoption" is certainly superlative. That existing sites rarely go through top-down redesigns is part of the slow adoption, though. Are there really designers who have been exposed to the idea of semantic design and yet are still making designs with <div> soup instead of <main>, <header>, etc? I would certainly hope not.


> Tailwind and similar frameworks divorce the concept of a semantic web we as a society have been building towards for decades.

We definitely haven't been building any sort of "semantic web", ever.

> It works against the idea that you mark up areas of your code with descriptive labels like "header"

You mean `.hero-text__sticky-container--secondary` and such. This neither is semantic nor decouples styles from the document.

> rather than separate the code from the appearance markup, it was generally considered to be a really bad idea.

People pretend that it is a bad idea. In reality "separate code from appearance" was dead on arrival. You'd be hard-pressed to find sites from any era of the web that didn't couple code and presentation (even if the two were in different files).

You only have to realise that separation of concerns cuts both ways: https://twitter.com/simonswiss/status/1664736786671869952?s=... (accessible to non-logged-in users)


At the dance time world you say the semantic web has arrived in the non tailwind parts of the web?


I guess it depends on what we mean by "arrived." Are the technologies present and can they be used well? I think so. Are they as widely used as they should be? Of course not. Is there room for improvement? Always.


When the semantic web was the new thing, it was similar to the hype cycles around new technologies or very early applications of it (nft, etc).

A contextual, connected knowledge base and digital consciousness never really came according to the semantic web specs in terms of implementation and adoption and use by the masses.

Still, maybe that middleman work is something LLMs could help with.


I've been using it over the last 6 months or so. I don't have a lot of web experience. Web UIs I've worked on before have been very barebones styling-wise. For this latest one I wanted to make it prettier. I hated writing CSS so I thought I'd try tailwind.

I've fallen into what I assume is a common trap with tailwind: I still know very little CSS and I've devoted headspace to remembering tailwind class names. Getting tailwind to do what I want, mainly with layouts, is hard because I don't understand all the underlying CSS and core principles. I wish I had instead knuckled down and learnt good CSS skills.

I think picking tailwind because you don't like CSS or you lack experience with it is a mistake. If you have experience and already have the mental image of what you want things to look like and how to achieve it, the utility classes probably make that quicker and easier to do.

Regarding the ugliness, I thought I was being clever by using `@apply` to make reusable components. And then I was surprised to read https://tailwindcss.com/docs/reusing-styles#avoiding-prematu... and it's preferred to use long lists of class names. Like multi-line editing is actually recommended as an ideal way to deal with duplication. I don't understand what's so bad about having to go find the class name in another file, and maybe make a new one or tack on some additional classes in the HTML. But again, I lack so much experience in this area and I'm working on relatively small projects so I don't have the same requirements and challenges as other users.


Having written production CSS for 15+ years across everything from global e-commerce Magento sites to new age Next.js RSC projects, I like Tailwind (after much conflict). The piece I feel like is missing in most explanations of why it “works” is the flow you can achieve with it. It’s a distinct difference. The idea of essentially hammer utility classes, all provided in one package, provides a novel experience that does stick.

As many will say, it’s biased towards component-based code, which I agree is where it shines the brightest. But even in my legacy Rails projects, I can’t shake the want for more utility/generalized classes.


It's basically in how you interpret "semantic naming". For some, they think in the "large font" or "large margin" as "semantic". Others only accept "header" as semantic.

There is undeniable coupling between CSS and HTML (and JS) for web apps. How willing are you to refactor those "header" CSS styles to maintain more semantic meaning is probably why you'd be on one side of the fence or other.

Tailwind is a well-designed shorthand system for CSS styles so it's reasonably easy to learn and then quick to type out and compact in the HTML file.

Tailwind is a pretty leaky abstraction too (thick border class will have a mention of "px" in it or positional specifiers like "bottom" maybe shortened to "b"), so it will feel really close to writing pure CSS styles to some.

In theory, you could also combine the two: have a class "header" and then define that in terms of Tailscale CSS classes, but once you do that, it really drives the question of "why use Tailwind?" home.


Tailwind can create bloated content.


There's no turning back from the expressiveness of Typescript, brevity of Svelte, reusability/portability of Tailwind and simplicity of golang once you've tried them.


Two decades ago I was overjoyed to discover that Scheme was finally going to have a useful application beyond illustrating SICP and writing koans to amuse myself, because DSSSL was on the cusp of evolving into the last document styling language anyone would ever need.

Unfortunately following an incident with a broken Lisp machine, a liquid lunch, and an unlicensed particle accelerator, I became trapped in a parallel universe where the HTML ERB anointed CSS by mistake during a drunken night out in Oslo.

The fundamental concept of CSS (best revealed by H.W.Lie's thesis IMO¹) was to create a rich and versatile and non-Turing-complete set of structural selectors in lieu of DSSSL's recursive logic, and to allow styles to overlay one another; two design choices that only by the application of gallons of irony can explain why most web pages are composed of a bunch of nested DIV elements with hashed IDs and overloaded semantic class attributes, and everyone compiles their assets into a static file.

Consequently, all CSS is crap. Tailwind is (in my experience and opinion) the least crap and most productive approach yet. I switched over years ago and have no regrets. Adam Wathan is the hero we deserve.

[1] https://www.wiumlie.no/2006/phd/css.pdf


I started teaching myself to code 8 months back. I was used to HTML/CSS so I used styled components initially. Someone persuaded me to give Tailwind a shot.

It was a little rough start but I now really appreciate the pre-built styles, the intuitive naming schemes, and the confidence that it will just “work” across devices.


Here's Rich Harris (creator of Svelte/SvelteKit) first impression about Tailwind:

https://www.youtube.com/watch?v=0bog8-Ay7CU&t=12849s

Timestamp in case link doen't work is 3h34m8s


I don't think tailwind is supposed to be used just as a sprinkling of css attributes throughout the html.

I thought the idea was to simplify making css frameworks?

Eg, it really is ugly when you have, let's say a <ul> and each <li> has the same bunch of tailwind styles - these should obviously be extracted into a 'widget-list' class or whatever.


Agree with author and the quote...after trying it, it really was like drinking the kool aid


The ugliness of vanilla CSS is in the absence of scopes, though it’s coming.

I was a big fan of Tailwind, but after switching to mostly Svelte, where CSS is scoped by definition, I found that the vanilla CSS is not as nasty as I previously thought.


Tailwind might as well be CSS now as far as I’m concerned. It’s been 3 years of greatness.


Meaningful class names were great. I could use them to reliably build filter lists for uBlock Origin and User Styles to fix bad design, but I can’t select on these classes at all.


> As I get deeper into my software engineering career I have realized an important aspect of what I consider "good" code is that it enables you to focus very tightly on the section you're working on without needing to jump around to other files (or even scroll down the same one.)

Agreed. But this point (and the next point) mainly seems to be a workaround for React not including single file components.

There’s very little reason to start new projects in React these days and while Svelte didn’t invent SFC (I think they came from Vue) your CSS is right there in the component file, automatically scoped to the component when you save.


CSS is water and Tailwind is PRIME drink.

Let's not dictate people what to drink. 90% of the time water is all you need.


More like CSS is well water and Tailwind is a good quality water filter.


All you need to know is this. Tailwind is beloved by Hacker News commenters with zero design sensibility or skill whatsoever, and typical zero front-end specialism as well. They may argue this, but then you only have to look at the projects they're using Tailwind on to understand.


I would love to see the CSS files behind your amazing Tailwind-free designs and know how easily a new dev/designer can jump in and make meaningful non-breaking changes. Especially if any of those projects have touched more than one team over a few years.



Sounds like its perfect for me. Finally we can get rid of pompous designers who all think that they're Johnny Ive.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: