I don't understand tailwind. The entire point of CSS is to separate style from structure. How does applying composable utility classes to all of your HTML elements differ from the old days of using HTML attributes for styling?
Edit: So after looking into it a bit more, and specifically the section in the documentation about extracting components, I understand where they're coming from a bit better. Extracting repeated compositions of utility classes into reusable components or named classes is exactly how I use other CSS frameworks such as bootstrap or foundation. I'm seeing the major difference between tailwind and other CSS frameworks as being the lack of pre-defined UI components. The minimalism is obviously a big advantage for performance, but otherwise I still see little difference between Tailwind and other CSS frameworks.
It really is one of those "you gotta try it" things.
Once you get over the small learning curve, it gets to be VERY productive. Think of it as writing CSS at a slightly higher level of abstraction. That abstraction being in not having to edit two separate files or areas of your HTML document (unless you want to abstract further with @apply).
Not having to go through the 'define identifier in element, then define in StyleSheet' workflow. With Tailwind you get the most commonly used style definitions pre-defined. But not so high level that it LOOKS pre-defined. Giving you room to customize greatly. How could it not be faster?
I recently completed a theme in Tailwind, mostly to get the hang of it: https://planflow.dev/free-themes/. And managed to go from idea to finished theme in about 4-5 days. That's the fastest I've ever done it.
FYI, URL routing is broken on that site: if you navigate to /free-themes directly (such as following a link), you end up at /, and can only access the right page by clicking the link in the navigation in a JS-enabled browser.
The problem is that devs stopped doing semantic elements. Its now a div and span fest. The layout however has become more simple due to mobile/smartphones. But the front end complexity has become exponentially more complex. You save one day of work by using a bunch of frameworks, then you have to pay every time a user visits - with less conversions due to a slow site. And then you have to pay every time you make an update - due to the extra complexity. Then you regularly have to pay over and over again to keep the frameworks up to date.
> The entire point of CSS is to separate style from structure.
Keeping your CSS and HTML completely separate just doesn't work in practice though e.g. we still need to throw in ad-hoc wrapper `div`s because CSS isn't powerful enough to do what we want, we have to pollute the HTML with class names that have little semantic relevance outside of styling as we're creating the styling, and it's a pipe dream that designers can jump in and help with the styling without help from the programmers.
It's a nice idea but keeping HTML and CSS 100% separate hasn't panned out - people need to accept that and stop promoting the separation of CSS and HTML dogmatically. The reason there's so many CSS frameworks and different ways to do the same thing on the frontend is a strong evidence we're still figuring out the best way to do things. CSS has been out for around 20 years now and it still doesn't do what we need it to.
Also, if you're keeping your data (like blog posts, product information) in a database, your data is already separate from your UI/styling. What are you gaining by splitting up your styling further? Is a similar level of splitting up done in other (non-HTML) UI frameworks?
Your last point is a new argument for me and is really understated. The HTML/CSS fragmentation appears to be a historical artifact more than an architectural ideal
I'm not sold on the idea, but there is one major difference: you constraint yourself to a set of values. This attains two goals:
(1) You have to think less. Try "margin-top medium", look at the result, "oh it's too much", try "margin-top small", look at the result, ok fine. No px-fiddling.
(2) It produces more consistent results (i.e.: things tend to look nicer).
What doesn't win me is that, while I see the increase in development speed this brings, I don't see how would you handle maintainability (i.e.: what happens when the design needs to change?). I suspect the trade-off here is that you just renounce to such redesigns and commit to the idea that you'll rebuild the entire thing if/when the time comes (tech advances so quickly in this space that you may want to do it anyway).
In practice with a similar approach, we have seen when design changes, you end up having bits of your site looking old indefinitely. You can tell the “era” a page was built based its design choices. Not good.
- Once you are in the "margin-top: xxx" part, nothing prevents you from saying "just this time" and writing some px (or whatever) value, either because you don't remember the options at your disposal, because none of them feel exactly right or whatever. Using tailwind you would have to create an entirely new size definition, which is a big hassle. That is, using scss does not actively push you to this particular "pit of success" whereas using tailwind does.
- Responsive handling is much more verbose in scss. Consider "sm:mt-2" versus "@include responsive(sm) { margin-top: margins(2) }"
One of the best things about Tailwind in my opinion, is that it makes a load of decisions for you.
Spacing, button styling, border radius, shadows, font sizing - basically the things its easy to get wrong - are already decided for you so its easy to make something that looks decent pretty instantly.
I have also been using Tailwind Builder[1] which is pretty helpful for learning Tailwind and also generating things like menus and basic page layouts pretty quickly.
Well the point of CSS separating style from structure is to be modular and useable across different websites/pages. So define a button class name I can use anyway in my HTML.
But the web environment has changed. React and Vue introduced modularity of style and structure with components. So I can just use a Button component across the website instead of a CSS class. This means CSS is mostly written only for that specific component or file. So tailwind and those other css-in-js have sprung up to bring both into one file.
And I’ve been using tailwind for about a year now and can very quickly throw together most layouts. It feels very smooth to be able to define the div and it’s style on one line at the same time. And short classnames like “m-4” and “w-full” are also more succinct than the raw html style property.
> React and Vue introduced modularity of style and structure with components.
It also works perfectly fine with server-rendered pages in my experience. Any templating engine worth its salt will allow you to extract fragments or partials.
> Start putting css in the style attribute while you’re at it.
I think everybody reacts like this at first (including me) :) If you put styles directly in the attribute, nothing is preventing your from using a color that's not part of your palette, nor using sizes that do not respect your UI "flow". Tailwind comes with a (customizable at build time) well-defined sets of colors and sizes.
The basic tension here is designers are often not really designing a "style sheet" (even if they think they are). So a lot of elements end up being similar, but not the same. And all responsive states are often 'you figure it out'. Plus marketing involves one-off pages where nobody is thinking about reusability. I haven't used tailwind yet, but the utility-first idea has been around for a long while.
They provide a balance of governance and flexibility that allows team members to work independently to create new designs, but not have CSS specificity get out of hand.
One main benefit is to constrain the actual power of CSS specificity.
The other main benefit is that these micro-styles map closely to design semantics, not functional semantics. This is covered in the OP. At a certain scale, the number of distinct functional semantics grows huge, but the design semantics remain bounded.
I personally don't think extracting component classes is a useful tailwind feature.
IMHO it is really quite similar to using HTML attributes for styling or inline styles. Maybe those wheren't actually such terrible ideas. They are the easiest thing for a beginner to understand, so maybe they are actually the easiest way to reason about styles for non-beginngers too.
What makes it different is:
- higher level component frameworks: wether you use react, vue, web components or use a templating engine in a component pattern, that is all the abstraction you need. Introducing an additional layer of abstraction/reuse with shared CSS classes is uneccessary overhead.
- constraints: the scales for spacing, color, typography and everything else that you configure for tailwind lead to nice, consistent designs without much effort. I think that would be a key problem when just using inline styles.
Another point that hasn’t been mentioned yet is Tailwind also minimizes regressions. With the blanket CSS way, changing a style has too many side effects and can mess up other styling that you didn’t intend on.
One benefit that isn't often mentioned is better developer ergonomics. Styling with utility classes saves you from having to open a CSS and html document side by side (e.g. if you do layouts where it's helpful to see the html structure while writing css), which can make a huge difference if you also need a browser window for visual feedback.
I think the most satisfying part for is the elimination of the constant context switch between my jsx/html and css file.
We use CSS modules and it drives me crazy to keep switching back and forth to add styles.
Plus is think <div className="mx-12 lg:mx-24 md:mx-12 bg:white dark-mode-bg:black />
looks just outright readable and tells me everything i need to know about that div in one glance.
I for one absolutely love it, but have team members little on the backfoot. Preferences i guess
bg:white is exactly the problem. What if I want to change all my white backgrounds to #FCFCFC? I've got the option of going through and updating all my components individually or updating bg:white to be a non-white value.
Everything is generated through a config file which you can completely customise. So you could literally change the colour of bg-white if you wanted to.
It's part of the selling point, that config file becomes your design system. They provide a decent one but you are free to overhaul it as you see fit. It works really well.
If you were building a themeable website, then you'd not be using bg:white; instead you'd use something like bg:main or something similar with a semantic meaning. This kind of customization is one of Tailwind's core workflow.
it's like variables for styling. Instead of throwing some random numbers developers can bump the numbers up p-3, p-4 or text-red-200, text-red-300. It helps to keep things consistent.
For a simple website semantic HTML or SMACSS can work, but for any semi-large scale websites with many variations of components it'll quickly descend into specificity hell. Using atomic classes keeps the specificity flat, and it avoids an entire category of errors that haunts many large projects just by making the styles sort of self-contained (you still need the stylesheet).
Of course there are other approaches to this problem such as "namespacing" your CSS using BEM and dynamically generating class names using CSS-in-JS, but using atomic classes is a very maintainable way to style HTML, if a little hard to read.
It’s a pity that literally every HN thread about Tailwind has someone that wishes to complain and moan about it. We get it, you prefer old school CSS spread across multiple files that you need open all at once.
I understand a lot of people still remain skeptical of utility-first approaches. And answering the same questions repeatedly gets frustrating.
However, please avoid the snark. It diminishes the discussion. It took me a long time to come around to the idea, and the snark of (some of) its supporters was precisely part of the reason for that.
Edit: So after looking into it a bit more, and specifically the section in the documentation about extracting components, I understand where they're coming from a bit better. Extracting repeated compositions of utility classes into reusable components or named classes is exactly how I use other CSS frameworks such as bootstrap or foundation. I'm seeing the major difference between tailwind and other CSS frameworks as being the lack of pre-defined UI components. The minimalism is obviously a big advantage for performance, but otherwise I still see little difference between Tailwind and other CSS frameworks.