esc
Anthology / Yagnipedia / Tailwind CSS

Tailwind CSS

The Framework That Replaced CSS With CSS, but Abbreviated
Technology · First observed 2017 (Adam Wathana); culturally dominant by 2022 · Severity: Polarising (developers either convert or write manifestos against it)

Tailwind CSS is a utility-first CSS framework that replaces writing CSS with writing CSS class names in HTML, which is a different activity in the same way that writing a letter and dictating a letter are different activities: the output is identical, the process feels different, and the recipient cannot tell.

Tailwind was created by Adam Wathana in 2017 and achieved cultural dominance by 2022, which is remarkable for a framework whose core proposition — “instead of writing padding: 1rem in a CSS file, write p-4 in your HTML” — sounds, when stated plainly, like a lateral move.

It is not a lateral move. It is, depending on whom you ask, either the most important advance in CSS tooling since Flexbox, or inline styles with a build step and a marketing budget.

The Proposition

Tailwind’s insight is that most CSS classes are written once, used once, and named badly. The class .card-header-title-wrapper-inner exists in thousands of codebases. It is used by one element. Its name communicates nothing that the element’s position in the DOM doesn’t already communicate. The class exists because “separation of concerns” — the doctrine that HTML should describe structure and CSS should describe presentation — demands a name, and the developer, who has named thirty-seven things today and is running low on creativity, supplies one.

Tailwind eliminates the naming. Instead of inventing .card-header-title-wrapper-inner and then writing its styles in a separate file, the developer writes the styles directly on the element using pre-defined utility classes:

<div class="flex items-center justify-between p-4 bg-white rounded-lg shadow-md">

This is readable to a Tailwind developer. This is hieroglyphic to everyone else. This is the trade-off, and the trade-off defines the community: those inside it cannot imagine going back, and those outside it cannot imagine going in.

The Squirrel’s Proposal

Tailwind appears twice in the lifelog, both times as a proposal from The Caffeinated Squirrel, both times rejected:

“FRONT-END! React! Next.js! A design system! Tailwind! Shadcn! A component library with—”
“I like templ. It makes for reliable fast pages.”
— The Caffeinated Squirrel and riclib, The Front Door, or The Night the Palace Finally Faced the Street

“DID SOMEONE SAY UI? I’ve been THINKING about this. React Native for mobile, Electron for desktop, a shared component library using—”
"—Storybook for documentation, Tailwind for styling, a design system with tokens and—wait, what?"
“We’re not building a UI.”
“We’re borrowing one.”
— The Caffeinated Squirrel and riclib, The Borrowed Palace, or The Night We Stole a UI With curl and Goodwill

The Squirrel proposes Tailwind the way the Squirrel proposes everything: as part of a stack. Tailwind is never proposed alone. Tailwind arrives with React, with a component library, with a design system, with a build pipeline. This is not Tailwind’s fault — Tailwind works perfectly well without React. But in practice, Tailwind is the styling layer of a JavaScript ecosystem, and the ecosystem travels as a unit.

The War Wounds

riclib’s relationship with Tailwind is not theoretical. It is documented in scar tissue. The progression — Pico CSS, Bulma, DaisyUI, Tailwind, shadcn/ui — traces a developer’s journey through the CSS framework landscape, each battle fought, each battle lost:

Pico was the straight jacket — a classless framework that styled everything by default and nothing by choice, resulting in eighteen months of inline style overrides (see: The Facelift, or The Day the Squirrel Won).

Bulma was the middleweight — a component framework with opinions about grids and cards that became constraints when the design disagreed.

DaisyUI was Tailwind with training wheels — pre-built components that saved time until they didn’t match, at which point the developer was debugging Tailwind utilities inside DaisyUI components, which is two layers of abstraction between intention and output.

Tailwind itself was the final conventional war. The utility classes are powerful. The utility classes are also a vocabulary. The vocabulary must be memorised. The vocabulary changes between versions. The HTML becomes unreadable to anyone who hasn’t memorised the vocabulary. And the moment the design requires something Tailwind doesn’t have a utility for, the developer writes CSS anyway — but now the CSS lives in a @apply directive inside a Tailwind config, which is CSS with extra steps and fewer features.

The conclusion, reached through combat rather than theory: build your own CSS. Per project. Per purpose. No framework. No vocabulary to memorise. No opinions to override. Just CSS, written by someone who finally learned it because every alternative to learning it proved more expensive than learning it.

The Two CSSes

The lifelog blog — built after the wars — has no CSS framework. It has 651 lines of CSS in a Go function. Seven storyline themes. Responsive layout. Dark mode. Wikipedia-style infoboxes. Zero utility classes. Zero !important declarations. Zero build steps beyond go build.

The Solid V4 product — built by one developer and eight AI agents — also has no CSS framework. It has its own: 34 CSS files, 13,000+ lines, a tokens.css design system with CSS custom properties, BEM-inspired naming conventions, and component files that map directly to product domains (chat.css, dashboard.css, forms.css, drilldown.css). The build step is go:embed. The files are plain CSS, embedded into the Go binary at compile time. No Tailwind. No Sass. No PostCSS. No node_modules.

The V4 CSS has 15 !important declarations across 13,000 lines — most overriding chart library styles, four for accessibility (prefers-reduced-motion), and three genuine workarounds. This is CSS discipline at scale, achieved not through a framework’s constraints but through a naming convention that one developer and eight AI agents all understand.

This is the answer to Tailwind’s proposition: you don’t need a pre-built vocabulary if you build your own. The V4 naming convention — .card__header, .btn--primary, .field__input--error — is as consistent as Tailwind’s utility classes, more readable than px-4 py-2 bg-blue-500, and understood by eight AI agents who learned BEM from the same training data they learned Tailwind from. The agents don’t care which vocabulary they speak. They care that the vocabulary is consistent. Custom CSS with clear conventions is exactly as learnable as Tailwind — the agents proved it.

Both projects — 651 lines in a string, 13,000 lines in 34 files — share one principle: no framework. The difference is not philosophy but scale. The blog is one file because it can be. The product is 34 files because it must be. Neither fights anything.

Measured Characteristics

See Also