Moving away from Tailwind, and learning to structure my CSS

88 points by dzwdz a month ago on lobsters | 51 comments

dkasper | a month ago

not sure if this opinion will be popular, but I don't typically use any css or javascript frameworks for my personal projects anymore. Can't have supply chain vulnerabilities if you have no dependencies! Of course that's only one type of vulnerability but it helps.

sebastien | a month ago

I'm also back to a fairly vanilla HTML/CSS/JS, sprinkled with hand-rolled stuff. It's a combination of framework fatigue, npm audit overload, and the fact that with LLMs I don't have to care anymore about what other people think about the implementation (eg. Why are you not using React and Tailwind?).

Pinning kinda saves you from a security perspective, but there's also the old fashioned strat of vendoring in the files as a one-off.

Ultimately though I do feel like on personal projects leaning into simpler build systems and the like is very helpful. I have found that having no build system or no framework leads to a lot of teeth gnawing, re-implementing some ideas from some library badly, and then finally just adding the build system.

Fortunately esbuild is decently simple and fast nowadays.

fleebee | a month ago

Pinning is a mitigation but it doesn't save you from supply chain attacks. Even if you have pinned your local dependencies to safe versions—which isn't a given—transitive dependencies might have floating version ranges.

Combining pinning with min-release-age is much more effective than pinning alone.

[OP] dzwdz | a month ago

What happened to just downloading the .css file for a framework and just putting it in your document root? You don't have to use npm if you don't want to.

That would be really inefficient for Tailwind (that's probably the main reason why I don't use it), but there are other frameworks out there.

hoistbypetard | a month ago

You can make it reasonable for tailwind by using their standalone cli. tailwind-py does that, and it's not bad if you're a tailwind enjoyer. (It's still my least unfavorite way to do css, even if I have some misgivings about it.)

[OP] dzwdz | a month ago

Then you're running some code provided by them on your computer, and that exposes you to supply chain attacks again.

You can run Tailwind in a container or sandbox it if you're concerned. Also, Tailwind has no dependencies, so you only need to trust the Tailwind developers (or audit their codebase), and you can pin a single version and use that essentially indefinitely.

I think you're right to be concerned in general, but in comparison to a lot of the Node ecosystem, Tailwind is a lot less likely to cause issues.

hoistbypetard | a month ago

That’s a fair angle. Using it standalone limits it by not pulling in all of the npm ecosystem, especially by reducing the likelihood of accidentally accepting an update.

yawaramin | a month ago

Yeah, Bulma works very well for my use cases.

if you use a lockfile your transitive dependencies won't change unless you ask them to change, and that change will be visible.

I wasn't clear that in my mind I was talking about a full pin (i.e. including the transitive deps).

fleebee | a month ago

That lockfile will need to be regenerated any time you upgrade your dependencies. The change is visible, yes, but at the point where you're taking the time to inspect the lockfile diff and verify the legitimacy of all the changed transitive dependencies you don't need any other precautions.

I know NPM and I believe other tools will not regenerate the entire lockfile, but rather only the portion of the dependency graph that is specifically being updated. But yes, if you update your entire dependency tree without looking at what dependencies are being pulled in, that can be an issue, and I agree that min-release-age and similar settings in other tools can also be useful here.

ocramz | a month ago

wait, how's CSS a vulnerability ? did I miss a new kind of spicy CVE

polywolf | a month ago

CSS itself is only mildly dangerous (see other comment), but installing it via package manager lets you do things like "run a post_install hook that steals ur creds" that most worms use to propagate.

hoistbypetard | a month ago

It's exactly this. NPM's default settings open you to this. I think it can be used in a way that's reasonably safe, but the "happy path" can quickly make you very unhappy if you get unlucky with timing.

[OP] dzwdz | a month ago

CSS can (used to be able to?) make external network requests depending on the page contents, see e.g. CSS Exfil (sorry for not linking to a primary source, but that article seems like a decent tldr).

I don't know how much of a concern that is nowadays, I think browsers have some mitigations against this nowadays? Malicious CSS would also be pretty low on my list of potential attack vectors tbh. CSS frameworks don't really have to be updated, and it would be hard to pull this attack off against a site that doesn't even exist at the time the framework is created.

I mean, yeah — this is how CSS works. People not knowing this and blindly using Tailwind make me want to step outside and yell at clouds for a while. To me, 90% of Tailwind is just inline styles with different syntax — it's arguably just one step above <FONT> tags.

Edit: I see how the above comment was unclear, I’m sorry. I’m yelling at clouds because this situation exists, people being led to believe that Tailwind is just a sort of subset of CSS, then years later having to discover that CSS is actually something else, with its own structure and philosophy and history that Tailwind deliberately rejects.

I’m not sure what your goals are with this comment, but I can say that in almost 8 years of using Tailwind I read a countless number of comments like this one dismissing Tailwind users and none of them helped me in any way to move off of it or to improve my CSS skills.

this blog post is me explaining what I actually needed to know.

I don't think being frustrated that people aren't using their tools to their best potential is "dismissing" them…quite the opposite, really. There are millions of CSS tutorials out there; I don't see why I need to write another one, if that's what you're suggesting.

All I'm saying is if you want to use CSS you should learn CSS. You yourself said it's fun and interesting! If you still want to use Tailwind after that, great, then it's an informed choice.

bitshift | a month ago

if you want to use CSS you should learn CSS.

It sounds like Tailwind was the way jvns learned CSS, though?

The trend seems to be arcing slightly away from Tailwind these days, but I'm considering learning it anyway because it might help strengthen my mental model. I've used CSS for a while, and I know at a logical level "oh, this thing does that, kinda" but I don't know it know it, and I'm curious if Tailwind would be a useful on-ramp to that. Certainly it worked for some folks when the CSS tutorials didn't.

To me, Tailwind is more like another styling system that compiles to CSS. It's from an alternate timeline where HTML decided to go all-in on inline styles and make them richer, rather than inventing CSS in the first place. It's not really the same model. And indeed one place Tailwind is useful is when you're using a component system like React, and you want do styles with your component renderer, so you want them to be independent.

[OP] dzwdz | a month ago

It sounds like Tailwind was the way jvns learned CSS, though?

As mentioned in her original Tailwind article, she's been writing CSS for 12 years before she learned Tailwind. Not that I disagree, "learned" can mean a few things, and she's probably gained a lot of experience during the 8 years of using Tailwind too.

yawaramin | a month ago

if you want to use CSS you should learn CSS

Why? Let people use what they want to use. Especially for personal projects, there's zero downside to experimenting with various technologies and in fact upsides from getting the experience and judgement to decide what they prefer. Not everyone has to learn in exactly the same way, and that's OK.

[OP] dzwdz | a month ago

I assume wrs refers specifically to writing "raw" CSS here. "If you want to use [vanilla] CSS, you should learn [vanilla] CSS" is reasonable advice, and I don't think it excludes using Tailwind (and learning Tailwind rather than vanilla CSS) instead.

yawaramin | a month ago

No, they are referring to Tailwind when they say ‘you should learn CSS’. Because after they say ‘If you still want to use Tailwind after that’.

AFACT, 90% of Tailwind is just inline styles with different syntax — it's arguably just one step above <FONT> tags.

That's not really very accurate, Tailwind behaves very differently to inline styles and much more similarly to CSS. As the author's article points out, a lot of the good habits that make Tailwind work well are the same good habits you need to write effective CSS. Tailwind is more like giving every element an implicit scoped CSS block, but with a funky DSL.

Your time spent yelling at clouds could be spent figuring what Tailwind is and how it works, then it might not make you so upset! ;)

giving every element an implicit scoped CSS block, but with a funky DSL

…in other words, an inline style with a different syntax? (I know, there's a little more to it than that, which is why I said "90%".)

I understand how it works — if a project has already commited to it, I use it. I do try my best not to have opinions about stuff I don't understand! Now ask me about Helm sometime. :)

…in other words, an inline style with a different syntax? (I know, there's a little more to it than that, which is why I said "90%".)

Not really? Inline styles are collections of properties. But CSS is those properties, plus selectors, pseudo-classes, combinators, @-rules, the cascade, and so on. The big issue with inline styles is basically that they can't do most of the things that CSS is designed to do.

But Tailwind can do all of those things, so the comparison with inline styles feels like a misunderstanding of what Tailwind is.

yawaramin | a month ago

I know, there's a little more to it than that, which is why I said "90%"

But it's not "a little more to it", that's exactly what I'm saying. Tailwind is to inline styles as CSS is to inline styles. Which is to say, inline styles are a list of properties, which exist in CSS, but a lot of the complexity of CSS (and Tailwind) is not in that list of properties.

That stat is made up by squinting at the TW codebase I'm in and estimating how many of the styles are mb-4, flex-1, w-12, and other things that translate literally to inline CSS. Of the rest of TW, subtract the part that (non-inline) CSS can already do, and you're left with not much.

I think the best quick way to access my feelings is this: Scroll down in the docs past the "Isn't this just inline styles? In some ways it is…", the reinvention of CSS variables, the special syntax for not using variables (?), the examples of how you'd do this in CSS that look more sensible to me than the thing that's replacing them. You will arrive at TW's recommendation for reusing styles on multiple elements — which is exactly what CSS classes are for, but in this alternate universe we used classes for something else. Their answer: multi-cursor editing???

re your edit: something that I maybe should have said in my post is that critiques of Tailwind and its impact on the industry like Tailwind and the Femininity of CSS had a big influence on my decision to stop using Tailwind.

I honestly probably started out with an attitude towards CSS a little like that post describes ("They’ve heard it’s simple, so they assume it’s easy. But then when they try to use it, it doesn’t work. It must be the fault of the language, because they know that they are smart, and this is supposed to be easy."). But while using Tailwind I came to really love and appreciate CSS as a technology, and appreciate why it's so complex. It's been so exciting to see CSS evolve over the last 10 years or so and it's one of my favourite things.

And now I'm inclined to think that Tailwind contributes to devaluing CSS as a skill. That's not something I want to participate in even though I found Tailwind personally helpful in my journey towards learning CSS.

Anyway this is all to say that I forgot in my original reply that there are important reasons that folks are frustrated about Tailwind and that I should have remembered that.

quasi_qua_quasi | a month ago

Quite the contrary, I’d argue that all programming is feminine as it was pioneered by women (who were then pushed out by men)

As a woman, I resent the implication that everything I do is "feminine". And I think it forces you to conclude that e.g. modern mathematics is "masculine".

nposting | a month ago

It's been a while since I read this post (thanks for linking it!) & I feel like the forces at play are even more transparent since it was published. Tailwind was one big push towards the full mechanization of frontend development, and now you can just extrude something that vaguely seems like a user interface if you don't care about any of that girl stuff. There's some kind of masculine expression in the current trend of hacker/gamer-aesthetic LLM-extruded throwaway websites that just describe the author's "real project" (usually some real macho stuff like a toy compiler!). In a way I think you can read the aesthetic trend as a flaunting that lost knowledge/ability to dominate the space

I love the 'extruded UI' metaphor.

I find that interesting, because I've always had the opposite impression — that there's a perception that Tailwind is for the weak and feeble, and Real Men™ use CSS. I wouldn't necessarily say that it's gendered (except for the general sense that challenge and difficulty are often coded in gendered ways), it's more like a "strong vs weak" thing.

I think there's also a big gatekeeping aspect to it as well (and Tailwind and the Femininity of CSS feels very gatekeep-y to me in this regard, although I think it also makes a lot of good points). Like "I had to learn CSS the hard way, so if you take any shortcuts, you're not doing CSS properly". But the point of CSS isn't the challenge, so that attitude always feels weird to me. I think it's important to expect people to achieve a certain mastery of their tools, but if a new tool makes it easier to achieve the same level of mastery, then to me that's a good thing. Using Tailwind well requires the same skills that it takes to use CSS well — you need to understand different kinds of selectors, as well as the cascade and specificity — because ultimately it is just CSS.

I also think there's a big divide between whether you style your website from the top-down (i.e. start with a single stylesheet and add increasingly specific rules for different elements as you work your way through the page) or bottom-up (i.e. start with all the smallest layer of components and then the components that wrap those, and so on going up the hierarchy). I think there's a certain type of person who feels that the former is the "correct" way to do CSS, and the latter is cheating in some way, but I think both approaches are useful in different contexts. And the two different approaches will naturally develop different tooling, so it doesn't surprise me that some people prefer not to use Tailwind.

Personally, I generally prefer working bottom-up (or at least, working bottom-up makes more sense for the types of projects I mostly work on), although I'm not a big fan of Tailwind specifically. But I find the weird criticisms people have of Tailwind more irritating than Tailwind itself, so I seem to often end up defending it in online discussions.

I don't mind a bit when there's a simplified version of something that helps you learn the real thing. That happens in every field: computers, music, physics, poetry. What I don't like is when something is presented as a simplified version, but it's actually a different thing.

Another example would be ORMs vs SQL. An ORM isn't a simplified version of SQL. It says right in the name, it translates between two different full-fledged paradigms, object and relational. That is not a trivial difference. It's not only not a simplification, it's a doubling (squaring?) of complexity, because you will eventually get into situations where something weird is happening and you really do need to understand object and relational to figure it out.

So I would never recommend that somebody use an ORM and claim it was helping them learn SQL. I would let them know that this is a useful tool that was built for a specific context. I'd warn them that although SQL is the layer below it, it is in some ways a contradictory model to SQL, and thus arguably it's working against their understanding of SQL. I'd also let them know that they will eventually, probably, have to understand SQL for real, at which point they will be able to make their own informed decision about when to use an ORM, SQL, or both.

doctor_eval | a month ago

There is a huge difference between knowing how css works and knowing how to use it effectively. I know perfectly well how css works but I still use tailwind because vanilla css is overwhelming and because I suck at graphic design. This article provides ideas for structuring css and uses tailwind as a base.

zladuric | a month ago

I also feel this way, and I'm not a CSS person at all.

I mean, the things the article says the author will now do is like reading good old smacss or BOM or something.

Not a ding on the author or anyone using CSS - if tailwind or bootstrap empowers you to make a website without having to learn a js frontend framework like react or angular, great!

But I do feel like people jump into it without knowing that they might not need anything beyond a tiny hand-rolled (or even llm-rolled) CSS file.

The article mentions that they ship 2.8MB! (minified!) of CSS! Really? That sounds like a freaking novel written in CSS, not a web app. You can ship entire apps in 3mb minified with CSS baked in, css-in-js style!

I get the appeal of getting something done (e.g. your blog) without having to learn the basics of your tools (like CSS). And I'm not complaining that people do use it.

I just don't like the situation for two reasons. One is that I now have to megabytes on most places of the web to read a simple story. The other is just a good old stubborn streak of someone who learned their first bits of html back when framesets were the thing, then made a mess picking up CSS randomly, then learned the core idea and the more advanced building blocks.

yawaramin | a month ago

I found this structuring technique very useful for organizing CSS: https://rstacruz.github.io/rscss/

It broadly agrees with and provides a bit more structure and organization on top of what jvns describes in OP.

doctor_eval | a month ago

This is great. Not “tailwind sucks just use css” but “tailwind is great but maybe you don’t need it any more”.

I’ve always struggled with manually structuring css and this article really made me think of it in a much different way.

[OP] dzwdz | a month ago

As someone who hasn't really been following along, this seems like a pretty good peek into modern CSS practices. I really like all the links to her inspirations, they seem like good reading (but so far I've only read "no outer margin").

I am, however, a bit skeptical of the "bottom up" approach for base styles? Not that I know what else I would do (and it still seems worth a shot), base styles are just inherently finnicky.

cespare | a month ago

I love this article. I also learned about CSS gradually over time by writing lots of random little sites, and I think that I would have benefited from thinking about these sorts of "systems" more from the beginning. I'm fairly allergic to frameworks but not using them meant that I often felt like I was floating in a bit of a structureless void even when I understood how to make everything work like I wanted.

pscanf | a month ago

I've used many CSS "frameworks" over the years, and the evolution of the codebase has always been more or less the same:

  1. Start out tidy, with a rigorous system for organizing styles.
  2. As exceptions emerge, expand the system to accommodate them.
  3. As exceptions keep emerging and you realize you'd need to overhaul the system to fit them in, go for some localized "hacks" instead.
  4. As exceptions keep emerging, give up and settle for following the foundational patterns 80% of the time, and hammering the styles until they look the way you want in the remaining cases.

I haven't had the chance to use Tailwind in a big project yet, but reading the post, I can see that it's not immune to this devolution:

I haven’t completely worked out an approach to managing padding and margins yet. I’m definitely trying to be more principled than how I was doing it in Tailwind though, where I would just haphazardly put padding and margins everywhere until it looked the way I wanted.

At this point the criteria I'd use to choose a CSS framework are:

  • Allows some level of encapsulation, so that the hacks stay confined to one component or section of the app/page.
  • Is the closest to native CSS.
  • Requires the least "build setup".

For my last project, about a year ago, I went with vanilla-extract. I don't really have any complaints so far, but it doesn't seem to bring any huge benefits either, so in hindsight, I probably should have gone with simple CSS modules, which seem to satisfy the above criteria the most.

I've long been a fan of CSS modules, and I'm a bit disappointed that the name has now been overloaded...

toastal | a month ago

You also make your markup more token efficient not being cluttered which 80% CSS utility classes 🙃

yawaramin | a month ago

Not to mention, more space-efficient.

toastal | a month ago

I use w3m & occasionally cURL, & yes, it is a ton of bits that don’t affect me as I won’t be seeing styles. I also maintain a couple of filter lists (ad block) & userStyles where the lack of meaningful classnames often makes it very difficult to fix websites with nothing stable to grab onto.

DanOpcode | a month ago

Inspiring article! Great thoughts. I want to do the same

hoistbypetard | a month ago

I enjoyed this piece! Tailwind is mostly the only way my backend-brained self has been able to do good things with CSS. I appreciate the direction the author is going, even as I personally plan to stick with Tailwind for a while yet. I do aspire to learning the same lesson and applying it to my work.