Julia Evans Ditched Tailwind — Here's How She Structures CSS Now

4 min read 1 source explainer
├── "Tailwind's utility classes obscure intent — named CSS classes are more maintainable for long-lived projects"
│  └── Julia Evans (jvns.ca) → read

Evans argues that utility class soup like 'flex items-center justify-between px-4 py-2' tells you what styles are applied but not why they exist as a group. For her workflow as a solo developer maintaining content-heavy, long-lived projects, named classes like '.article-header' communicate component intent immediately, making code comprehensible months later without mental re-parsing.

├── "Tailwind creates concrete refactoring friction that undermines its productivity promise"
│  └── Julia Evans (jvns.ca) → read

Evans identifies that when you want to change how a repeated component (like cards) looks across a site, named classes give you one place to edit. With Tailwind, you're either using @apply (which Tailwind's own docs discourage as defeating the purpose) or doing find-and-replace across scattered utility strings, making global design changes unnecessarily tedious.

└── "Tailwind solved a real problem for component-framework teams, but the backlash represents legitimate experience-based critique, not aesthetic preference"
  └── top10.dev editorial (top10.dev) → read below

The editorial notes that Tailwind has essentially won the CSS debate for React/Vue/Svelte projects and dominates npm downloads. However, a growing counter-current from developers who've used Tailwind for 2-3 years is now articulating specific, experience-based objections — a different category from the initial 'ugly HTML' aesthetic complaints that Tailwind advocates easily dismissed.

What happened

Julia Evans — the developer behind wizard zines, known for her clear-eyed technical explainers — published a detailed post about migrating her projects away from Tailwind CSS and developing her own approach to CSS organization. The post hit 468 points on Hacker News, triggering one of those rare threads where experienced developers actually share concrete techniques rather than relitigating framework wars.

Evans' core argument isn't that Tailwind is bad. It's that for her workflow — solo developer, content-heavy sites, long-lived projects — Tailwind's utility-first approach made it harder, not easier, to understand what her CSS was doing six months later. The class soup of `flex items-center justify-between px-4 py-2 bg-white border-b` told her *what* styles were applied but not *why* they existed as a group or what component concept they represented.

Why it matters

This post lands at an interesting moment in the CSS ecosystem. Tailwind has essentially won the "how do we write CSS in component frameworks" debate for React/Vue/Svelte projects. It's the default choice in Next.js starters, it ships with every UI component library, and its npm downloads dwarf every alternative. But there's a growing counter-current from developers who've used Tailwind for 2-3 years and are now articulating specific, experience-based objections — not aesthetic preferences.

Evans' critique centers on three concrete problems:

Readability decay. When every element carries 8-15 utility classes, scanning HTML to understand layout intent requires mentally parsing each class and reconstructing the visual result. With named classes, you read `.article-header` and know what it is. With utilities, you read the implementation details every time.

Refactoring friction. When you want to change how "cards" look across a site, named classes give you one place to edit. With Tailwind, you're either using `@apply` (which Tailwind's own docs discourage as defeating the purpose) or doing find-and-replace across templates — which assumes your cards all use identical class combinations.

Specificity as documentation. Evans found that a well-structured stylesheet acts as implicit documentation of your design system. The cascade, when used intentionally, communicates hierarchy: base styles, component styles, state variations, overrides. Utility classes flatten this hierarchy into a single layer.

The HN discussion revealed a sharp divide along team-size lines. Developers on large teams with high turnover consistently defended Tailwind: it eliminates naming debates, prevents specificity wars between team members, and makes code review straightforward because the styles are visible inline. Solo developers and small teams consistently reported the opposite experience — Tailwind added indirection without solving problems they actually had.

What Evans actually does instead

Rather than adopting a methodology like BEM or SMACSS, Evans describes a simpler approach built on modern CSS features:

Scoped specificity via nesting. CSS nesting (now supported in all major browsers) lets you write styles scoped to a component without any tooling. A `.post-list` block contains all its children's styles in one nested block — readable, greppable, and impossible to accidentally leak into other components.

Minimal class names that describe purpose. Not `.flex-row-gap-4` but `.tag-list`. Not `.text-lg font-bold text-gray-900` but `.section-title`. The class name is the abstraction; the properties are the implementation.

Custom properties for theming. Instead of Tailwind's config file generating utility classes, Evans uses CSS custom properties for her design tokens — colors, spacing, typography scales. This gives her the consistency benefits of a design system without generating thousands of classes she'll never use.

File organization by page/component. One CSS file per major page or component group, loaded where needed. No single 4,000-line stylesheet, no complex import trees. Simple and boring.

The approach works because Evans' projects have specific characteristics: she's the only developer, the sites are content-focused (not app-like), and they need to be maintainable for years without active development. These constraints make different tradeoffs optimal compared to a SaaS product with 15 frontend engineers.

What this means for your stack

If you're starting a new project, the decision framework is clearer than the tribal debates suggest:

Use Tailwind when: your team has 5+ frontend contributors, you're building a component-library-backed application UI, you want to eliminate CSS-related code review discussions, or you're prototyping and speed matters more than long-term structure.

Use structured vanilla CSS when: you're solo or a small team, your project is content-heavy, you value reading your styles as documentation, you want zero build dependencies for CSS, or you're building something that needs to work in 5 years without maintenance.

The real lesson isn't "Tailwind bad" — it's that CSS organization is a skill, and frameworks can prevent you from developing it. Evans specifically calls out that she had to *learn* how to structure CSS after years of letting Tailwind handle it. That learning has compounding returns: it transfers across projects, frameworks, and decades of web development in a way that Tailwind-specific knowledge doesn't.

For teams currently on Tailwind and happy with it: nothing in this post should make you switch. But if you've been feeling the maintenance friction Evans describes — difficulty understanding old code, `@apply` sprawl, or a nagging sense that your HTML is doing too many jobs — her post provides a concrete, non-dogmatic alternative path.

Looking ahead

CSS has quietly become remarkably capable in the last two years: nesting, container queries, `:has()`, `@layer`, subgrid. Each of these features reduces the problems that CSS methodologies and utility frameworks were invented to solve. The question for the next few years isn't "Tailwind vs. vanilla" — it's whether the platform improvements make the framework overhead unnecessary for most projects, the same way jQuery became unnecessary when browsers standardized DOM APIs. Evans' post is an early data point suggesting the answer is yes, at least for a significant segment of developers.

Hacker News 648 pts 364 comments

Moving away from Tailwind, and learning to structure my CSS

→ read on Hacker News

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.