I agree with you in the general case, but many people are going to be using Tailwind as part of a build step, and many of those people will be using Vite to do that build. Two options down is the option to install the CLI, which does not require any other build tools.
As for why it requires npm: I dislike the Node ecosystem as much as the next guy, but it’s a tool used for web development. Where else are you gonna install it from?
npm is for designed primarily for js dev. Many (most?) sites aren't written in js -- they're written in Java, C#, Python, PHP, etc.
Thankfully, tailwind is available directly as a downloadable binary. Unfortunately the link in their beta docs is buried, and also broken -- the correct link is here:
To answer your question sincerely, Tailwind is a series of utility classes that make it easy to author CSS within HTML (pages or components). Back in the day we had many libraries to do this, the most popular was called Bootstrap. It looks like this: https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootst...
You'll notice that Bootstrap CSS includes every single utility class within Bootstrap. This is fine, but it could be a lot smaller - reducing page load times for clients and data transfer for servers - if the CSS included by a library was solely the CSS used by one's site, and no more. This is why we web developers use an npm/vite build step generally, even if our out is very plain static HTML/CSS.
"Well why can't I just use Tailwind like I do with bootstrap? I just want to play around with it and not have to learn all that build stuff."
> You'll notice that Bootstrap CSS includes every single utility class within Bootstrap. This is fine, but it could be a lot smaller
For perspective, a build process that removes unused tailwind classes can result in .css files of around 10kb. But a .css file with entire tailwind framework is about 2.5MiB.
Also: When served from a CDN like your link above, popular CSS like Bootstrap had a decent chance of _already_ being in your browser's cache, so despite downloading more initially you'd come across sites using the same version that meant _no_ delay downloading CSS for it.
> Most importantly: cached content is no longer shared between domains. This is known as cache partitioning and has been the default in Chrome since October 2020 (v86), Firefox since January 2021 (v85), and Safari since 2013 (v6.1). That means if a visitor visits site A and site B, and both of them load https://public-cdn.example/my-script.js, the script will be loaded from scratch both times.
It was (and still is) never a good idea to hotlink to an external dependency.
Most developers know better than to hotlink to an image because it might one day return a completely different image (and potentially an unsavory one) yet they casually use external code dependencies.
It is also why the Dependabot(sp?) that has become so popular among devs makes me nervous. Something automatically updating your dependencies is a recipe for disaster.
While I don't disagree (broadly speaking) with you about the complexity of webdev, it looks like you don't have a full understanding of what Tailwind is:
a (CSS) code generator.
It happens to be written in JS so it can be integrated as part of existing build steps or bundling. That's the rationale behind it. :)
It's build-time, not something client-side.
So Vite is a security measure against opportunistic theft? Theft of what?
Hey, I yearn for the days of good car analogies too. But the car key is not an essential part of the car experience, rather a necessity borne of the distrust of follow man.
Because if you are working with CSS, there’s a decent chance you’ll be using npm and/or Vite, and it’s convenient to integrate your tools to save yourself time. Don’t like it, pick another installation method, like the standalone CLI build option, that needs neither.
Are you just lazy? Apart from not being up to date with common ecosystems (which I'd expect when doing anything web), look at the Getting Started:
Getting started
->Installing with Vite
->Installing with PostCSS
->Installing the CLI
->Upgrading from v3
At the bottom of the CLI paragraph it says "You can also download standalone builds of the new CLI tool from GitHub for projects that don’t otherwise depend on the Node.js ecosystem."
They just put the most common stuff at the top, because that's what most devs will use.
Software is required to "help" with CSS. Only seems reasonable that you'd need to install said software. Installing the Tailwind package provides the Tailwind software. So when you build your website that uses the `block` class, that class actually exists somewhere - because you pulled it in with the installation via the package manager.
Surely we can agree that distributing shared libraries via a package manager is a good practice, no?
CSS is text. What's wrong with copying the required CSS stylesheets over and including (importing) them from your own stylesheets?
Surely we don't need a "package manager" and a "build chain" for this?
Then again, I'm a person that writes any web-related code (HTML, JS, CSS, etc.) by hand.
Where did we take the left-turn of not understanding how things work on the actual tech level? These tools hide all of the actually required steps to npm-infested bloat.
x86 ASM is text but we don't build software by copying and pasting it. While the underlying thing we ship is CSS, that doesn't mean we can't add tooling layers to make it easier or more efficient. While it's totally allowed to write by hand, most frontend web developers I know are very comfortable with NPM, and indeed having dependencies consumed from a package manager is often preferred.
> Surely we can agree that distributing shared libraries via a package manager is a good practice, no?
At one point, long ago, you could just download a file, reference it in your index.html, and use it without ever having to worry about updating this package. It had its flaws, but it also had many advantages compared to having an external dependency that might conflict with your version of Typescript, or being highjacked by bad actors.
I don't diss the concept of package managers at all, but there are lots of case where vendoring an external package is preferable than adding it as a dependency.
Only parts of modern web dev are unnecessarily complex. What you can do with frameworks like SvelteKit or Nuxt, SolidStart, Remix, Next, ... is amazing. For simpler use-cases you sure can and should use vanilla HTML, CSS and some JS maybe some HTMX to level the interactivity ceiling, but for highly interactive apps with flexible rendering you need one of the modern frameworks. I assume you lack experience in front end, so believe me, getting started with a simple React SPA pre CreateReactApp (6-8 years ago?) was a horror trip. Now, starting, working on and deploying an app with the modern frameworks, e.g. SvelteKit doesn't get any easier in any tech. As a long term full stack dev my assessment is that web dev is in an exciting phase. A lot of innovation (and improvements) has been made in the recent years. Tooling has greatly improved mainly thanks to Vite, reactivity has become simpler, DX is a prio 1 concern thanks to Svelte. While not being fully convinced of general usefulness of universal rendering, I admire the innovation there.
Webdev is a shitshow so investors money could burn quicker. Huge potential for companies that can come in and transform the stack by throwing away the whole "modern" JS stack and use things like Turbo or LiveView
Agree, and the most maddening thing is that the platform is honestly better than ever. Doing your layout in CSS is so much easier now than it was 10 years ago, thanks to CSS variable, containers queries, and widely supported flexbox & grid.
It's the NPM ecosystem above that's being stupid, and believe that adding more tools and more processing is a good thing.
This is such a biased take.
There's many ways to build a website, you just don't like the most popular way because you're not comfortable with the technology and ethos.
That's ok, but don't go around spouting nonsense about about investors throwing their money away on js projects.
That’s on you. Vite is the de facto standard bundler today and one of the best things to happen to the frontend ecosystem in the last few years. Without even using it, do yourself a favor and check it out.
Looks like you are not really familiar with how Tailwind works. And if you don't understand it of course Vite or a build step will look weird. But I suggest first getting familiar with the thing you are discussing to avoid adding misguided comments to the discussion that really don't add any value.
Though you are of course correct, I see no problem with somebody reading about technologies that they themselves don't use here on HN. I personally read HN to get familiar with new technologies that I may find useful in my work and private life. I first heard of OpenAI and Anthropic here.
I resisted using it for a long time, it just seemed too much like read-only code for me. But I've been building my latest project with it, and I have never iterated on the front end more quickly. It is great fun.
this is the honeymoon phase, wait until your package manager and transpiler is out of date, and your progressive web app framework is out of date, and your typescript version isnt compatible with the upgrade yet, and tailwinds isnt either or it is but none of the documentation is yet, but you have to upgrade because your CI/CD cant run your version of node anymore
and now you have 100 flags across 5 configuration files and dont know which one to change to make everything work, but changing it might break the ability for a random dependency to compile, and even if you get that to work it turns out your project doesnt render anymore
Good rant! That's kind of what web-development seems like sometimes. Almost every part of the technology stack is there to fix some other part of the stack that never was ideal to begin with. TypeScript being the best example. It only exists because JavaScript sucks, and JavaScript only ever existed because in 1994ish some guy failed to get Java to run in the browser, and the only reason we're building apps in what was originally a "Document Rendering" system (HTML) was also not by design either but just an accident of history. One train wreck after another.
no, it's not a good rant. this is the billionth "web dev is too complicated!" rant that is present under every. single. thread. about any technology vaguely related to front end development.
I haven't yet reached the end of the comments, but I'm also fully expecting at least one "Electron is a cancer that is eating my computer and the reason why my wife left me".
This site leans heavily backend it seems.
There's a strain of patent smugness that comes with a lot of comments about frontend on this site and it's quite disheartening to see it.
You rarely see frontend devs disparaging backend devs for their tech choices.
I think back-end development is a much more "comfortable" lifestyle (I'm full stack myself), even if lots of it is technically more difficult coding than front end (i.e. multiple threads, databases, load-balancing, etc), because there's a new front end technology that comes out every couple of years, making many of the front end tech stacks become obsolete rather fast and they're super fragmented in terms of large numbers of different and unique frameworks. Not to mention how plagued front end work was for so many years due browser incompatibility issues.
For example, on the back end in Java there's been just basically SpringBoot for a decade, and as long as you keep up with it's minor changes you're all set.
I get where you’re coming from, but I think it oversimplifies the challenges front-end developers face, and it feels a bit dismissive of their expertise. Front-end development isn’t just about chasing frameworks—it’s about crafting intuitive, performant, and accessible user experiences in a landscape that’s constantly evolving to meet user needs.
Backend stability has its advantages, but the rapid evolution on the front end reflects a response to real-world challenges—like improving developer ergonomics, addressing accessibility, or enhancing performance. Front-end devs often have to bridge the gap between design, user needs, and tech constraints in ways backend systems rarely have
In the end, the fragmentation you see in front-end frameworks is a strength. It’s not “easier” or “harder”—just different kinds of challenges. Both disciplines are vital, and dismissing one does a disservice to the teams and individuals who keep these systems working in harmony.
It's not "dismissive" or a "disservice" to say which things I found harder in my 35yrs experience.
I also say C++ is "harder" than Java, and that's not "dismissive" of Java devs. lol. I AM a Java dev. I did C++ for 10 years followed by Java for 25 yrs after that, so I feel justified to have opinions. I could also say Assembly Language was hardest of all but I won't because it might be "dismissive" of any easily-offended C++ devs. :)
It is an interesting concept that backend is harder while so much easier. Maybe frontend is harder and it is difficult because you lack the necessary knowledge to make it as easy as you think backend is.
I just started HN a few months ago, so I haven't been around long enough to realize there's certain topics the HN aficionados have grown bored with. My apologies for the disruption.
What do you think are the best option to avoid that? I was wondering what could I do with a project that I have that is a long lived code base, so we have some legacy parts.
Looking at the alternatives I was considering Vite with React and Vue plugins (and try to migrate my code so it works by default without any other configuration in Vite) or try Astro (because I have Vue and React) with their default configuration, but still not sure what would be the best option.
If it where just for me I would rather use React like framework (while I don't like that much React) but at least bun supports JSX out of the box and they seems to be working towards having a bundler integrated.
I've been using it for a long time now and the honeymoon period hasn't ended. I do understand what you're saying, but luckily I keep it pretty simple with a standalone tw executable and no node.js or complicated frameworks, so I have been able to avoid these pitfalls.
i've been using it for... years? and it still feels like magic when i use it. v4 fixes my only real issue with it which was the config file feeling so detached and rough compared to everything else.
CSS modules is a (great) mechanism for providing isolation, very useful in the context of today's component-oriented front end development.
Tailwind provides some (quite good) building blocks for a design system, such as a palette, a sizing scale, values for shadows and rounded corners... and a vast set of classes to apply them. The set of classes covers basically every CSS feature, making it possible to slap everything in the class attribute of your HTML elements and never or almost never have to deal with CSS files.
In other words, CSS modules is a solution for those who love CSS and needed just a way to not deal with naming clashes without resorting to BEM. Tailwind is a tool for those who very much would like to avoid writing CSS
Maybe I should revisit this stuff. I’ve been fighting anything other than my own custom CSS classes for a while. It’s beginning to look at bit dated and I have no interest in rewriting them for the few sites that I support (family members and a couple of charities). I am no web guru and much prefer my hobby/day job of embedded stuff that you’ll never see on a GUI. I keep hearing great stuff about tailwind though.
i was all-in on simple hand-rolled CSS for the longest time but finally gave Tailwind a try because of a work project. it was a pleasure to use once i did.
i like to use it with DaisyUI also. the part i like is that all the classes i need are already written so its just putting pieces together.
I don’t work on the frontend very often, I think the last time I did so was when bootstrap was “the tailwind”, but when I recently had to cover for one of our react developers I got to work with it. I genuinely didn’t think there was a difference in my work flow between the two. Looking up meta language magic in the official documentation and then using it through brute-force development. Maybe I’m missing something, more likely I’m just a terrible frontend developer.
The latter is true either way. These days I’ll use HTMX and let a LLM do the CSS. Unless I specifically have to work on something which faces customers. So I’m wondering if there is some trick to tailwind I’m missing?
Bootstrap is so much worse because of all the nested CSS styles. One of the big benefits of utility classes is that they’re relatively isolated to one element (with a few exceptions like tailwind’s group classes). This has a lot of benefits like eliminating spooky action at a distance and making elements so independent they can just be copy pasted between Tailwind projects.
If you’re brute forcing Tailwind then you need to study CSS fundamentals. The vast majority of its utility classes are essentially 1:1 translations of CSS properties with some syntax sugar and DX improvements. Translating them to custom classes is a mechanical process even without @apply. There are even browser extensions like Windy that can rip HTML elements with arbitrary CSS to Tailwind classes.
OKLCH is widely supported in all modern browsers.[1] My easiest winning point with getting teams to start with OKLCH is that we can 'programmatically' control the color shades and tints by tinkering with numbers/values. To the designers (who don't write codes), I tell them that they can now focus on choosing the key colors (primary, accent, etc.) and then let CSS do the magic.
A good friend maintains a tool to tinker with various shades/tint of colors with OKLCH https://colorcolor.in
According to this article [1] OKLCH accounts for biases in human perception of color brightness. Seems useful, but I don't know the answer to your question.
First, note that all colors in sRGB can be losslessly converted to OKLch (but not the other way around), so I don't know if this actually changes the colors or not.
The reason to use OKLch is so that when using CSS color mixing (via animations, gradients, etc), they look "better", as indicated by the sibling comments.
OKLCH has the main advantage of LCH, which is that the numbers make sense, meaning that if you have two colors that are the same lightness they will look like they are the same lightness, because the numbers make sense you can now do programmatic color manipulation - increase lightness by 5 etc. that in the past would have been too difficult to really do (so people would instead just have variables giving the different rgb values and switch them in)
OKLCH just basically exists because there is a hue change from blue to purple in LCH when the lightness goes less which does not match how humans think of these colors (supposedly, don't know if there is any cultural difference)
So in OKLCH the lighter blue does not look purple like it does in LCH, it looks like lighter blue.
Oklch is a polar colour space corresponding to the rectangular Oklab, designed as a perceptual colour space, matching how people see things, rather than how display technology works.
There are three things to consider here:
1. Colour interpolation, as used in things like linear-gradient() and color-mix(). The default of sRGB is not particularly good; choosing Oklab or Oklch instead will normally improve things. Oklch is an okay default these days. I reckon that for most applications, Oklab is better. Oklch tends to be too vibrant in the most extreme cases like #ff0000 → #0000ff. Here’s a simple demo you can play with:
2. Specifying colours that are beyond the sRGB gamut. This is what they say in https://tailwindcss.com/docs/v4-beta#modernized-p3-color-pal...: “taking advantage of the wider gamut to make the colors more vivid in places where we were previously limited by the sRGB color space”. Frankly, this is seldom actually advisable. For most purposes, sRGB is quite enough, thank you: go beyond it, and your colours will be too vivid. In photographs it makes sense, but for colour palettes used with blocks of colours and such, it’s normally a bad idea. Yet if you are trying to go beyond sRGB, meh, nothing wrong with writing it in Oklch. Though color(display-p3 ‹r› ‹g› ‹b›) may be easier to reason about—
3. Specifying general colours. I’ll be blunt. Perceptual colour spaces are horrible at this. With things like HSL and LCH (and even display-p3 colours), you get values in a known range (e.g. 0–100%, 0–360°, 0–1), and they all work. With things like Oklch, do you know how thin the range of acceptable values is? Just try working with yellow, I dare you, or anywhere at the edges of what things are capable of. As a human, you cannot work with these values. You have to treat them as opaque, only to be manipulated by colour-space-aware tools. To take the most extreme example, take #ffff00, which https://oklch.com/ says is approximately oklch(0.968 0.21095439261133309 109.76923207652135)… whoops, you already slipped out into Rec2020 space. And it goes approximating it to #ffff01, anyway. And fairly minor adjustments will take it out of any current (or probable!) gamut. Just look at the diagrams, see how slim the area of legal values is at this extreme.
Perceptual colour spaces are really good for some things: interpolation, and some data visualisation palette things. But beyond that, you’re in a digital world, and a limited world at that, and they’re actually quite difficult to work with, and you should normally stick with #rrggbb. Especially if you have any interest in working near the maximum of any colour channel.
As an example, look at a place oklch() is used in that document:
I don’t know how they chose those numbers, but there’s no low-order polynomial curve there; they seem entirely arbitrary choices. Not a good showing for Oklch. The “modernized P3 color palette” shown is just as bad: all of L, C and H seem arbitrarily chosen. If you’re going to do it like that, you’re completely wasting your time putting the numbers in a perceptual colour space.
To be clear: Oklch is way better than RGB for some things, but it’s downright terrible for some purposes (often because you do actually care about the display technology, rather than a theoretical model of how vision works), and a lot of the claimed benefits for some purposes don’t hold up to real analysis.
Any thoughts on what color space you'd prefer to use? I'm working on a Tailwind palette creator (https://www.inclusivecolors.com/, it's based around letting you visualise the curves you mentioned), which uses HSLuv right now to avoid problem 2 in your list. HSLuv has perceptual uniformity as well (which is great at helping you pick colors that contrast) but it doesn't support P3 unfortunately, similar to Google's HCT color space.
I'm not seeing much demand for P3 at the moment though. Most designers I've spoke to don't know it exists.
I'm really curious as to why they felt the need to work on improving performance.[1]
Were people complaining it was too slow? Were the performance improvements just the benefit of refactoring they did for other reasons?
Considering the build happens once during your build phase, taking under half a second doesn't seem like something I would even bother looking at. So it just jumps out to me, so I'm just curious.
I think a lot of the optimization work was for dev time and it carried over to build time. I listened to a podcast interview with Adam Wathan where I think he said they just got really into shaving nanoseconds. They have a very successful business and I think they just enjoyed doing this work. On the other hand I do think even if you’re cutting from 50ms to 5ms (both low numbers in absolute terms) there are often new unforeseen workflows that become possible once you can do that operation so frequently that it’s free. You could do it on every keystroke.
> there are often new unforeseen workflows that become possible once you can do that operation so frequently that it’s free. You could do it on every keystroke.
That’s really interesting to think about actually! What kinds of practical things do you think could be enabled by an extremely fast tailwindcss?
I'm probably not going to be the one to figure them out, but like I suggested, hot reload on every keystroke is the first thing that comes to mind. It's probably better not to think of Tailwind CSS on its own here, but rather as one super fast part of a broader super fast build pipeline. Making Tailwind fast just means it's not the blocker. Imagine combining 10 or 20 tools that all have sub-millisecond incremental build times.
LLM trying design using tailwind, stuff like: try to recreate this bitmap image using tailwind utility classes; the iteration speed for that kind of tasks depend on such speed.
I think the rewrite aimed to simplify installation and configuration. TW 4.0 switched from PostCSS to LightningCSS [1], and Rust-based tools tend to offer a simpler setup via single binaries (in contrast to the complexity of typical JS-based tools).
Moving from pure JS to Rust also brings performance gains. Even if the main goal wasn't "performance," it's a nice side effect worth highlighting.
I absolutely care about things that take hundreds of milliseconds for my builds. The faster I can build, the faster I can iteratively try new things things out. The goal should be to be able to see changes instantly after you make them, and Tailwind is usually just 1 part of a build pipeline.
Bret Victor's Inventing on Principle is probably the best demonstration of why this matters; in the first 10 minutes he shows a very concrete example of an insight that would not have occurred without instant feedback https://www.youtube.com/watch?v=EGqwXt90ZqA
> I absolutely care about things that take hundreds of milliseconds for my builds. The faster I can build, the faster I can iteratively try new things things out. The goal should be to be able to see changes instantly after you make them, and Tailwind is usually just 1 part of a build pipeline.
When we're talking about ms the build is not the thing that is affecting your ability to try new things out. It was already so fast it was near instant.
If you want to try new things out and move fast with your CSS, you're not building the entire system. It's a partial build and that was already faster than you would even be able to react. Your browser refreshing would take longer.
Despite tailwind 3 being very fast there are situations where it can be a little slow and it adds up. I’m personally really glad they’re tackling performance in v4.
Given its popularity this can actually get into measurable carbon emission savings. Not world changing. But maybe a few international flights over the lifespan.
The carbon cost of a bloated CSS framework isn't the build time, it's the billions of times the resulting CSS has to be parsed and applied on the web pages where it's used.
Have you examined the build artifacts of a site using tailwind? The size of the CSS is often smaller than the same styling in "normal" hand written CSS. There are a dozen blog posts from large engineering orgs that have confirmed that switching to Tailwind slimmed their builds down. Shopify has been a big proponent of Tailwind and they are absolutely obsessed with shipping as little code as possible because of the scale they operate at.
Also, browsers are insanely good at parsing and applying CSS. You need hundreds of thousands of unique selectors before the browser takes more than fraction of a second to parse and render an entire CSS file.
CSS first configuration is a good change! It seems like it would makes it easier to combine tailwind with regular CSS files which still uses the same design tokens. This is useful e.g. when creating a site with a component architecture where the components are styled with CSS, but some of the content comes from CSS or markdown.
Tailwind threads usually include comments and questions that are answered in the documentation, so here's some useful links for people that haven't used Tailwind before.
A core part of Tailwind is that you reuse styles by using a templating system vs using custom CSS classes e.g. you have a button.html file that contains the styling for your buttons for reuse, so you don't have to keep repeating the same utility classes everywhere.
> It’s very rare that all of the information needed to define a UI component can live entirely in CSS — there’s almost always some important corresponding HTML structure you need to use as well.
> For this reason, it’s often better to extract reusable pieces of your UI into template partials or JavaScript components instead of writing custom CSS classes.
@apply (e.g. .btn { @apply py-2 px-4 bg-indigo-500 text-white }) is only meant for reusing styles for simple things like a single tag and is generally recommended against because you should use templates instead:
> For small components like buttons and form elements, creating a template partial or JavaScript component can often feel too heavy compared to a simple CSS class.
> In these situations, you can use Tailwind’s @apply directive to easily extract common utility patterns to CSS component classes.
Inline styles can't be responsive and can't target hover/focus states e.g. there's no inline way to write "text-black hover:text-blue py-2 md:py-4 lg:py-5 lg:flex lg:items-center" and the CSS equivalent is very verbose.
> But using utility classes has a few important advantages over inline styles:
> Designing with constraints. Using inline styles, every value is a magic number. With utilities, you’re choosing styles from a predefined design system, which makes it much easier to build visually consistent UIs.
> Responsive design. You can’t use media queries in inline styles, but you can use Tailwind’s responsive utilities to build fully responsive interfaces easily.
> Hover, focus, and other states. Inline styles can’t target states like hover or focus, but Tailwind’s state variants make it easy to style those states with utility classes.
Opinion: As utility classes are quick to type and change, and it's easy to find where you need to edit to change the styles of a component, it's an order of magnitude quicker to iterate on designs compared to CSS that's scattered across files and shared between pages in hard to track ways. CSS specificity and cascading aren't often used, and mostly just cause complexity and headaches so are best avoided. Tailwind-style vs classic CSS is similar to composition vs inheritance in OOP with similar pros/cons, where complex inheritance is generally discouraged now in OOP languages. Yes, the Tailwind approach is going against the standard CSS approach, but CSS wasn't initially designed for highly custom responsive designs so it's not surprising if its "best practices" don't fit everywhere.
Also, Tailwind is really for custom responsive UI and website designs. If your site is mostly Markdown documents and you don't need a custom design or complex mobile/desktop styling, the above isn't going to make any sense and plain CSS or something like Bootstrap is likely a better choice.
Yes! This sums it up perfectly. To the latter point, it's more so a tool for building design systems that comes with a [very large and thorough] default implementation.
I prefer scoped css, eg svelte or react with CSS modules. This allows one to closely pair the styles with the component, but still separate out the styling from the html (I cannot stand tailwind/inline syles)
Sometimes it’s necessary when using tailwind (I often use traditional CSS for animations). What’s the hip way to have CSS specific to a component? I remember StyledComponents from years ago. I wasn’t as much into front end then.
YMMV but I find ‘lg:…’ to be much better than ‘@media (min-width: 992px) { … }’ at the expense of repeating ‘lg:’ every class. Since most components don’t need too many responsive classes per breakpoint, this is a net benefit most of the time (and nothing is stopping devs from combining utility classes and custom css with media queries).
Like GP said, this kind of specificity is impossible in inline styles altogether which is relevant when not using CSS-in-JS in React et al.
The clamp() CSS function (and auto-adapting grids) can reduce media query usage to a really loooow minimum. Nowadays I use media queries only for mobile nav and maybe layout grid adaptation. Like 2 to 4-5 media queries per project maximum.
I think that's what the comment you're responding to meant.
After some experimenting I found that Tailwind works best with hybrid approach. The essay[1] is correct, that often you have one-of-a-kind blocks, like headers, footers, etc. that you can just fully implement with TW utilities, reducing cognitive load for class naming and structuring. But for more reusable elements, like buttons, links, inputs, popups, it's just much nicer to have them (and their variations) behind simple `btn btn-blue btn-small`. Even when using component-based approach, it's just much simpler to manage all those various states as explicit classes, rather than re-implementing CSS cascade in JS to determine how to combine corresponding TW utilities. I feel like if Tailwind Labs would be less radical in their marketing strategy, it'd receive a bit less of a backlash. Maybe :)
And I do agree, that moving to better integration with native CSS is a step in the right direction, very curious about future of v4
But all the real goodness is in contain[2] (which sounds the same but is not related).
Tailwind really needs to support contain. I am disappointed by their statement that there will be no major additions, because contain is really that important - both from a dev perspective, and from a performance perspective. It belongs in v4 from the start.
I invite (for fun and learning!) anyone here still thinking native CSS provides no efficient solution to the problems Tailwind may have solved 5 years ago to challenge me:
Bring up any said problem and I'll give you an efficient, robust, fast, simple and maintainable way to solve it in pure, native CSS (maybe even with further advantages!).
The time has come to embrace good ol' CSS again! Heheh.
I'm a new user of Tailwind, but there are 5 points where I believe Tailwind is wayyy more efficient than CSS:
- layout: flex and grid are great solutions, Tailwind just makes them extremely easy to use. Flex and grid are barely unusable without first defining at least 4 or 5 helper classes, more likely a dozen. Tailwind just provides them and makes them easy to use. I never could remember the flex properties, I learned the Tailwind classes I needed in like half a day of practice
- mobile first design: Tailwind strongly encourages mobile first design if you want to do responsive design. It scared me at first because media queries are hard to manipulate in CSS. I've never made a responsive design page faster than with Tailwind, it's insane how easy it is
- dark mode: as simple as `dark:xxx`. The default and dark properties being close together is awesome. As with responsive design, Tailwind prefixes make it so easy to do what's painful in plain CSS
- defaults: having sane, overridable defaults for everything (sizes, colors, whatever) makes the code infinitely more consistent. You barely even need to think about real values, just how it looks, and you have less risk of defining slightly different classes for no reason
- no cascading: CSS cascading makes it hard to reason about styles, and easy to break unrelated components by mistake. It's solved with CSS modules (or even with BEM), but Tailwind just eliminates the problem
CSS has the solutions, it just doesn't make them easy to use.
1. I don't think I understand why you think flex & grid are barely unusable... without a dozen classes..? Maybe an example would clarify this perception for me.
2. You barely need media queries anymore for responsive design. Auto-adapting flex or grid containers and the use of clamp() reduced 90% of my media query usage. I usually use like 1 to 4 media queries in project (for master layout and responsive nav, for example). And there's a nice side effect to this type of intrinsic design : layout and type is way easier to optimize for every viewport! Mobile first design is really easy to approach in this way.
3. You can apply a dark mode by only switching a theme file with design tokens inside. Way lighter, way easier to read, does not clutter your codebase.
4. As a corollary to the previous point, the defaults you are talking about can be CSS custom properties defined in a theme file as I think, Tailwind 4 will do. You could then use the exact same defaults in native CSS.
5. Simple rules about CSS usage, enforced by Stylelint for example, can prevent the vast majority (and maybe all!) of the cascading problems you mention. Here are some rules and a Stylelint config I posted in a reply below: https://ecss.info. I've got a good track record with teamwork and this config.
CSS solutions may be really easy to use when approached properly. I'm happy to follow up with examples and/or reply to subsequent questions and thoughts!
Ok, my problem is that I don't know just by reading the styles that other contributors wrote, whether they are still relevant, or if the HTML they applied to was changed or removed. They didn't write clean atomic commit, and I can't get them to adhere to some sort of convention.
The other problem is that I don't have a designer and tend to make things ugly given full freedom, but I do want things to have their own visual identity.
1. I address the problem of relevance by inserting the CSS right into the component with a link tag. If the component is not used, the CSS isn't either. A positive side effect of this technique is that you always have an easy access to the CSS by following the link in your editor of choice. As for the relevance of the rules inside the component, the said component should be light/simple enough that this isn't harder that glancing a minute (max!) at both files.
2. You can use Stylelint to ensure adherence to specific rules. I have developed a config aiming to prevent these kinds of problems. You can find rules, guidelines and a link to the Stylelint config (still beta) at https://ecss.info.
3. A CSS theme file with custom property design tokens is sufficient. As I understand, Tailwind 4.0 made the switch to CSS tokens. You can thus use the same naming convention for your tokens in native CSS.
As complementary advantages you get future-proof code, no build step, and a lot less unused CSS (for instance, Tailwind's own homepage sports 85% unused CSS!).
I'm happy to elaborate further or respond to any subsequent questions you may have!
> I address the problem of relevance by inserting the CSS right into the component with a link tag. If the component is not used, the CSS isn't either.
Do the selectors in those style tags not apply globally? How do I prevent contributors (including myself) from accidentally writing a selector that affects HTML in other components? I see ECSS allows plain tag selectors for example?
Isn't the design token variable file quickly going to balloon? As you mention, it looks like Tailwind provides this now as well, but you'll still want to run the build step of generating the minimal style sheet that provides only the tokens you actually use, rather than having to compile that style sheet manually.
As a related question: if you're already running Stylelint, what's the problem with a build step?
And: is the CSS on Tailwind's homepage actually unused, or used in dynamically added HTML? Is the additional download+parse size actually significant, or does it e.g. compress well and not affect performance that much? Throttling network speed at least doesn't result in a terrible loading experience for me, it seems.
1. The stylelint config will flag any selector not scoped (be it a class or an attribute) to the filename. This way you'll be notified if any selector could be misapplied essentially preventing these global accidents.
2. You could use a build step for this, yes. Personally, I don't because the theme files more or less contain always the same tokens. I rarely add any (colors being the most frequent) and if I do, the cost of it being unused is minimal. My standard full theme file is around 5kb.
3. Stylelint complements my work but isn't necessary. My code does not depend on it to work, contrary to Tailwind, for instance. I'm free to stop using it any time.
4. It's a monolothic file containing all the code needed for the whole site and not only the page I'm looking at now. It may not make that much of a difference in performance, but still, the browser downloads CSS code it does not need now and then must read through all of it to apply needed rules. Not optimal.
By the way, it's great you came back with further questions! Hope to have addressed them at your satisfaction. Still at your disposal if you have more!
But on the ECSS homepage I see selectors like `html`, `.flex-module` or `.is-loading` (I'm assuming `flex-module` and `is-loading` aren't components - if they are, then that sounds like being pushed towards a layer of indirection that I'd like to avoid?) - aren't those likely to affect other components?
What's the disadvantage of not being able to stop using Tailwind at any time? How likely is that to play out?
Why does it matter if something's "not optimal" if it doesn't make much of a difference in performance? (See also: not removing unused styles from your theme files :)
1. some simple selectors can be used in specific contexts (like `html` for type inheritance, for instance). `flex-module` is a component name (albeit a very generic one only used for example purposes...) and `is-loading` is a "state class". I use simple prefixes to distinguish between selector types and `is` is one of them.
2. Breaking changes could be introduced through the Tailwind dependency tree. Some update could be necessary to patch an exploit, again breaking functionality. Updates become routinely necessary. Which is not the case for native code. Also, using new CSS features can be more taxing within the TW ecosystem than in with vanilla CSS. In a nutshell, it's about simplicity, maintenance and the perenniality of your code. On the other hand, you may be "lucky" and never experience something like the above. But I'd wager there's more chance that you will than not. At least, my own dev experience tells me this.
3. Well, I'd say it's a matter of scale... I see 60kb of CSS on Tailwind's homepage. If more than 80% is unused, that's something like 45kb of CSS. I think at this amount, you could see marginal improvements in rendering and loading. At least, more than with comething like 2-3kb of unused CSS. Hehe. But yeah, as I said, marginal. BUT! hehe, with a less monolithic approach to bundling CSS, as with links in components, for instance, there's a real gain to be had: the browser delays reading the files not being used in the current viewport. So, if you footer is not displayed in the first screem it's CSS won't be read, accelerating overall rendering. This, in my experience, makes a palpable difference.
Hope I'm being clear, english is not my first language. And thanks for the mental workout! Hehe.
> Bring up any said problem and I'll give you an efficient, robust, fast, simple and maintainable way to solve it in pure, native CSS (maybe even with further advantages!).
I'd like to not have to read or write CSS. Let's see you tackle that. ;-)
Well, Tailwind doesn't really solve that for you either - you pretty much have to know CSS to be able to use it effectively, in my experience. Technically, you may not really be writing CSS, but in practice, I think all the reasons you might have for not wanting to write CSS still apply to writing Tailwind.
1. you need to know the specific effects of the individual directives but you don't need to deal with the cascading behaviour and other complexities.
2. you don't need to leave your local markup to make styling changes.
3. you don't need to synchronize selectors across multiple files (non-locality).
And because Tailwind involves a lot of repetition of the same CSS classes for the same markup, it naturally drives you towards defining reusable HTML components that encapsulate the markup and CSS classes.
There are a lot of subtle usability improvements like this that avoid CSS footguns and make dev UX better overall.
1. Which part of the cascade do you struggle with? Because it can make your code really simple and efficient!
2. If you link your CSS inside your component you have a direct access to it. A simple editor split suffice to edit it. I would say that's a pretty standard workflow.
3. You can force (with Stylelint, for instance) the use of scoped selectors in CSS files, essentially preventing any selector spillover (which is a real problem). Scoping component selectors inside the one and only corresponding CSS file is important and achievable without complex code dependencies.
4. The drive to define reusable components should already be natural enough on its own! Heheh.
By approaching CSS with the good tools and mindset, you can have a great dev experience while preventing complex dependency chains, third party rules/lock-in. You can also use the most recent CSS features not implemented in Tailwind (looking at you clamp()!) to provide a better end-user experience more easily.
That's fair enough, but I do still expect that someone who really wants to avoid CSS will still be put off by the extent to which Tailwind still is, in essence, CSS. I think Tailwind has advantages (the ones you note), but "being able to not learn CSS" is not it.
> Installing with Vite
What the hell is Vite? Oh, it seems to be something you need to install via npm.
I cannot help but to ask - why do we require npm, or Vite, for something that looks like it should "help" with CSS?
Why is the webdev such a shitshow, that seems to get ever deeper into its own weird rabbit hole?
reply