CSS frameworks have come and gone. Blueprint CSS, 960 Grid System, Foundation, Bootstrap - each had a moment and then receded. Bootstrap still has enormous install counts but has not defined how new projects are built for years.

Tailwind CSS is different. It is not receding. Every year since 2020, its adoption has increased. The 2024 State of CSS survey showed it used by 78% of respondents, with satisfaction scores that do not typically come from dominant tools. Developers do not just use Tailwind; they prefer it.

Understanding why requires understanding why every alternative failed to fully solve the CSS problem.

What Was Wrong With the Alternatives

Bootstrap solved the blank-page problem. You got a grid system and pre-built components immediately. The problems: every Bootstrap site looks like a Bootstrap site, customizing beyond the defaults requires overriding CSS specificity in ways that are painful, and the bundle size includes styles for components you are not using.

CSS Modules gave you locally scoped class names that avoided global namespace collisions. This was a genuine improvement. The problem: you still wrote CSS. All the cognitive overhead of managing specificity, cascade, responsive breakpoints, and naming conventions remained. The naming problem - card__header--active - was still your problem.

CSS-in-JS (styled-components, Emotion) moved styles into JavaScript. Benefits: true colocation of styles with components, access to JavaScript variables for dynamic styles, proper encapsulation. Problems: runtime overhead for parsing and injecting styles, poor performance for server-rendered apps, complex setup, and a significant cognitive overhead from styling syntax in JavaScript.

SASS/LESS gave you variables, nesting, and mixins on top of CSS. The problems: variables are now solved by CSS custom properties, nesting is now native CSS, and mixins are powerful but verbose. SASS is still useful but no longer solving problems that vanilla CSS cannot.

Each alternative solved some problems while introducing others. Tailwind’s insight was that the problem was not CSS syntax or scoping or preprocessing. The problem was making decisions.

The Tailwind Insight: Constrained Choices Are Better

Adam Wathan articulated the core insight clearly in “CSS Utility Classes and Separation of Concerns”: writing CSS for any component requires an indefinite number of micro-decisions. What color? What exact shade? What font size? What margin? What border radius?

Without constraints, every developer on a team makes these decisions differently. The result is visual inconsistency and a stylesheet that grows indefinitely as every component gets unique values.

Tailwind’s design system gives you a constrained set of options. There are not infinite shades of gray. There is gray-50, gray-100, gray-200, through gray-950. There are not infinite font sizes. There is text-sm, text-base, text-lg, and so on.

When you build with Tailwind, you are not writing arbitrary CSS. You are choosing from a curated set of design tokens. The result is visual consistency without effort - because the options are constrained.

<!-- Instead of writing arbitrary CSS values -->
<div style="padding: 24px; background: #f9fafb; border-radius: 8px; border: 1px solid #e5e7eb;">

<!-- You use Tailwind's design tokens -->
<div class="p-6 bg-gray-50 rounded-lg border border-gray-200">

The second version uses values from the same scale every other component uses. Consistency is structural.

The Colocation Benefit

Traditional CSS requires context switching between HTML and CSS files. When debugging a component, you navigate from the template to the stylesheet, find the relevant class, check for overrides in parent components, and trace the cascade.

With Tailwind, all styling information is in the markup. You can understand what a component looks like without leaving the HTML file. For component-based frameworks like React, Vue, and Svelte, this colocation aligns perfectly with how developers think about components.

The “separation of concerns” objection - that mixing style information into HTML is wrong - does not hold for component-based development. The concern is the component. The component’s styles are part of the component’s concern.

The Just-In-Time Engine

Early Tailwind generated a large CSS file containing every possible utility class. Even with PurgeCSS removing unused classes, the development experience was slow. The Just-In-Time engine, introduced in v2.1 and made default in v3, changed this.

JIT generates CSS on-demand as you write classes. The development experience is instant. The production bundle contains exactly the CSS your project uses, typically 5-20 KB after compression for a large application. There is no purge step needed.

This also enables arbitrary values:

<!-- Tailwind v3 with JIT - arbitrary values when you need exact pixel control -->
<div class="w-[347px] top-[117px] bg-[#1da1f2]">

This safety valve means you never need to leave Tailwind for edge cases. You can drop into arbitrary values for the 5% of situations where the default scale does not fit.

Adoption Numbers Tell the Story

Framework npm weekly downloads (2025) GitHub Stars
Tailwind CSS 9M+ 83K+
Bootstrap 5M+ 170K+
styled-components 3M+ 40K+
Emotion 4M+ 17K+
CSS Modules N/A (bundler feature) N/A

Bootstrap’s star count reflects its longer history and massive installed base. Tailwind’s download growth trajectory is the relevant signal - it has been the fastest growing CSS tool for three consecutive years.

What Tailwind Does Not Solve

Component patterns still require work. Tailwind provides utilities, not components. Building a dropdown, a modal, or a date picker in Tailwind requires composing utilities and managing interactivity separately. This is why shadcn/ui and similar component libraries built on top of Tailwind have become popular - they solve the component pattern problem that Tailwind deliberately leaves open.

Long class lists can be unreadable. A button with hover states, focus rings, dark mode variants, and responsive sizes can have 20-30 utility classes. This is a real readability concern that Tailwind’s @apply directive or component extraction partially addresses.

Onboarding requires memorizing class names. Developers new to Tailwind need to learn the utility class names before becoming productive. The IntelliSense plugin for VS Code and Neovim makes this faster, but there is a real ramp-up period.

Bottom Line

Tailwind won the CSS wars by solving the root problem: decision fatigue and inconsistency from unconstrained styling. A curated design token system with utility classes forces consistency structurally, colocation with markup matches how component-based development actually works, and the JIT engine provides excellent performance with zero configuration. The weaknesses - verbose class lists, no built-in components - are real but addressable. The alternative frameworks solved symptoms rather than the underlying problem. Tailwind solved the problem.