Live data from Hacker News

Moving away from Tailwind, and learning to structure my CSS

jvns.ca

311–320 of 435 posts

Re: Moving away from Tailwind, and learning to structure my CSS

#311
Once upon a time, whenever I interview developers, most of them proudly announced their expertise in jQuery. I have to bring them down to the basics and ask them about JavaScript. Almost all of them were lost. I asked them, if not for this, but to learn JavaScript and all the other framework will that; a framework on top of JavaScript which one can just use (perhaps take a week or so ro learn).

The same goes for CSS. Everyone bolded, and highlighted their experience with Bootstrap but missed the CSS. I did used Bootstrap, Foundation, Skeleton, Bourbon, and many others, especially when working with the team, so we all can speak the same language. This is true for Tailwind too. I remember when Tailwind was still in alpha and I realized that was the perfect tool to bring the team together and move fast. I was able to use it both as a utility and like most other people as the HTML polluter (but it worked).

If one is keen, it is always a good idea to learn the core - HTML, CSS, JavaScript; all the frameworks that wraps them should just be syntactic sugar. Bootstrap came and went, so will Tailwind.

PS. With AI/LLM Coding Assist, writing in plain CSS is becoming beautiful again. I can outline what I want, give it a checklist and make it do the strenuous part of writing them. I don’t even have to remember the cascades.

Re: Moving away from Tailwind, and learning to structure my CSS

#312

Earlier quoted context omitted.

that’s exactly the part that is anti locality of behaviour. I don’t want/need cascade. I only care about components and building up from them. And I would rather have it be explicit over implicit and scoped/encapsulated. Call it composition over cascade. To be clear I think it’s possible to do this without tailwind. And tailwind has other out of the box features/opinions. But it works well enough without too much fri…

> that’s exactly the part that is anti locality of behaviour. It is not. Because it fits the concept of "web pages" as documents and forms (which most web apps are, even if they're trying to pass as desktop applications. > I don’t want/need cascade. I only care about components and building up from them. And I would rather have it be explicit over implicit and scoped/encapsulated. And you're very welcome to do what y…

End users and even other programs/extensions can load rules to alter your styles. I think thats about as opposite of locality of behaviour as it gets. (no judgment on customization on being good/bad).

With the rest I don't really strongly disagree. I think its just a question of complexity. For simple things its fine, but for complex apps with teams of people :shrug:

Re: Moving away from Tailwind, and learning to structure my CSS

#313
I have found some nice middle ground with Frankenstyle [0] framework which take some inspiration from Tailwind (and Shadcn) but with no-build, which is the thing that I found really annoying with Tailwind. CSS with a build process is already not css anymore. But I understand the feeling of OP to want a cleaner code - without sparkling style details all over the html, though overtime I do feel it really gets out of hand and in the end having the styling in the html makes it less complexity to manage which class is where.

[0]: https://franken.style/

Re: Moving away from Tailwind, and learning to structure my CSS

#314
post #172

Earlier quoted context omitted.

How are ARIA roles/attributes bad for accessibility? Sure, if there is a HTML element that works then use it, but not every UX pattern is expressible in HTML without specifying roles/attributes (e.g. tabs [1]) and not all browsers support recent HTML elements/attributes (such as using details/summary for accordions). ARIA patterns [2] has a list of examples for UX components and their examples specify/use ARIA roles/…

WAI's APG patterns exist to document how ARIA attributes should work, they don't advocate for them to be used in place HTML elements. They also don't test to confirm that they actually work in browsers or with assistive technologies (some specific patterns are fine). For web developers, they're helpful for documenting expected keyboard interaction support and other norms. Are you still coding to support Internet Expl…

Details/summary had quirky/inconsistent handling by screen readers for quite a while after it reached full browser adoption, unfortunately. Not even sure if they’ve fixed it here in 2026, honestly.

https://www.scottohara.me/blog/2022/09/12/details-summary.ht...

While it’s good to use well-implemented semantic elements when possible, there are still plenty of places where either the built-in browser behavior isn’t actually very accessible (like native form validation), or where you just can’t avoid it (using aria-disabled instead of disabled for submit buttons, setting aria-pressed for toggle switches, setting aria-expanded for buttons that trigger modals, situations where you need aria-hidden/sr-only, etc).

Though once popovers and the invoker command api hit baseline widely available, we’ll be able to drop some of that.

Re: Moving away from Tailwind, and learning to structure my CSS

#315
post #310

Earlier quoted context omitted.

I think this assertion is where most of the conflict comes from. There is a fair amount of people that disagree with the premise that it should be separated in that way (Including me). I personally like this essay by the author of htmx on the topic https://htmx.org/essays/locality-of-behaviour/ Also just better composition imo. Practically I think this means components of scoped css, html, js. People never seem to ha…

There’s absolutely no tension between locality of behavior and separation of concerns in CSS: you’re putting styles on the elements in the document . The styles are defined elsewhere. It’s like arguing that all of your source code should go in one big file because one file is less than two files, which means greater localization.

Its arguing that that source code that affects the behaviour of something should be easily discoverable from the point/points its behaviour affects. or alternatively more indirection/obfuscation is worse.

Its not so much about same file, as reducing distance to understanding, whether visually or by some sort of easily traceable path.

Like you would want to init a variable closer to its usage, Or that having a 100 wrapper functions is less understandable than inlining for a single statement, or global mutations are harder to trace then local, and that sometimes its easier to inline a single sql statement then split it out into a different file just because its 2 different languages.

Also, to be clear its possible to write CSS that exhibits less or more LoB. The file thing is more that I don't think HTML, CSS, JS "must" be written as separate files which is what the prevailing best practice used to be, justified as SoC. I just think splitting along the scope/behaviour lines rather than file type is more understandable.

Re: Moving away from Tailwind, and learning to structure my CSS

#316
post #305

CSS Modules are a simpler solution to cascading problems. They create unique class names, so your classes don't clash [1]. And they don't have the two main downsides of TW, which are readability [2] and tooling. Tooling for debugging and experimenting interactively with Chrome and FireFox DevTools. [1] https://x.com/efortis/status/1888304658080256099 [2] https://github.com/ericfortis/tailwind-eye

Don't most modern CSS tools create unique class names? I know styled-components did. Recently I've been using linaria which is a drop-in replacement for styled-components (exact same API) but its zero runtime. All the CSS is compiled during build (similar to vanilla extract, panda CSS, etc). I really prefer things like styled-components or Linaria or CSS Modules where you can just write straight up CSS. If you ever d…

True, I didn't mean to omit other solutions, I thought styled-components were deprecated after React 18.

Re: Moving away from Tailwind, and learning to structure my CSS

#317

One approach I've been really starting to enjoy is to use use Tailwind alongside scoped styles (in Svelte and Vue). This keeps template pollution minimal while still allowing for the conveniences Tailwind brings: + {{ count }} @reference "tailwindcss" .counter-component { @apply flex items-center gap-2; button { @apply bg-gray-800 text-white; } .count { @apply italic text-teal-500; &[data-is-even="true"] { @apply tex…

yeah, likewise, I locked in on this very early on even though it goes against what the tailwind creators recommend. But I've never regretted this approach and it works well.

Adam always did say best practices don’t work.

Re: Moving away from Tailwind, and learning to structure my CSS

#318
post #186

Earlier quoted context omitted.

I disagree with that conclusion. I see tailwind as a cleaner more succinct version of css that is much easier to manage and add features too. Sure it’s not as dry, but I’ve been bitten in this regard because css framework and templates are so intransparent, preventing me from simply changing padding or margin. CSS is too detailed and too verbose. Frameworks like bootstrap are too high level and don’t give enough cont…

> Sure it’s not as dry, but I’ve been bitten in this regard because css framework and templates are so intransparent, preventing me from simply changing padding or margin. How does this happen? You can always override css values. Either by ordering, !important, inline or, to make very sure, with inline !important.

[deleted]

Re: Moving away from Tailwind, and learning to structure my CSS

#319

Earlier quoted context omitted.

> tailwind frees you from having to spend excessive time building abstractions of styles/classes that will invariably change. Abstractions like a hero image, a menu, a headline? Sure, it's easy to overthink things but most of the time, it's not that complex. > placing the styles directly into the markup that is affected by it reduces cognitive load, prevents excessively loose selectors In my opinion, it's the opposit…

Premature DRY and premature attempt at separation of concerns have resulted in absolutely horrible spaghetti code in too many code bases. Many times it's fine to repeat yourself. Many times it's fine for a component to cross multiple concerns.

DRY is critically important as it pertains to correctness. If DRY is hard to achieve for technical reasons then back-reference comments and whatnot can suffice, but you really do want only one owner for each meaningful fact in your codebase.

That's not to be confused with syntactic similarity. I largely don't care if you have ten different identical circular buffer implementations, so long as semantically it's correct that when one changes the others don't. Depending on the language maybe it would make sense to use type aliases or extract some common subcomponents or something, but duplication itself isn't a problem.

Re: Moving away from Tailwind, and learning to structure my CSS

#320

Earlier quoted context omitted.

With CSS names are global. You have to be careful not to accidentally create a class that conflicts with another one used elsewhere in a different context. You have to worry about whether modifying your class will have downstream effects on elements you weren’t intending to impact. It’s a giant pain. I’ve done it by hand for around 20 years before switching to Tailwind. Can vanilla CSS be used for a complex app? Yes.…

> With CSS names are global. In your "programmatic" code (your JS/TS, python, C++, whatever..) your classes are global. Even if the language supports flexible namespaces, or module scoping, you still have to take great care naming because reusing a name will cause you confusion. Giving two things the same name makes them harder to import, and risks clashes and bugs. No-one complains about this. This is just how you c…

In "programmatic" code, declaring two classes with the same name in the same namespace is generally either some sort of syntax error or one will "shadow" the other; it doesn't just silently merge the behavior of both classes.
Post reply on HN