June 2026
Why I Stopped Using Tailwind and Went Back to Plain CSS
A developer's honest account of why utility-first CSS failed in real projects and why plain CSS won back their workflow
I’ve built websites for over a decade. When Tailwind CSS exploded, I adopted it eagerly, convinced utility-first was the future. But after three major projects, I found myself fighting the framework more than the design. I stripped it out and went back to plain CSS. Here is exactly why.
The Illusion of Speed
Tailwind promises rapid prototyping, and it delivers—for the first few hours. You throw classes like flex, p-4, and bg-blue-500 onto HTML, and a decent-looking component appears instantly. That initial burst feels addictive. I remember a client project where I built a hero section in fifteen minutes using Tailwind. I felt like a god.
Then the real work began.
The Readability Tax
A typical Tailwind component looks like this:
<div class="relative flex flex-col items-center justify-center min-h-screen bg-gradient-to-br from-blue-900 to-indigo-800 text-white p-8 md:p-12 lg:p-16">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight mb-4">Build Faster</h1>
<p class="text-lg md:text-xl max-w-2xl text-center text-blue-200">Some descriptive text that goes on for a while.</p>
</div>
Now imagine this pattern repeated across forty components. Your HTML becomes a dense, scrolling wall of abbreviations. Reading it requires constant mental parsing. You scan for text-lg, then md:text-xl, then lg:text-2xl—each line a tiny puzzle. In plain CSS, that same hero would have a class like .hero with five clean rules in a stylesheet. Your markup stays readable. Your brain stays uncluttered.
The Real Bottleneck
Here’s the truth most Tailwind advocates don’t tell you: writing CSS is rarely the bottleneck in a project. The bottleneck is understanding the design system, debugging layout issues, and maintaining consistency across pages. Tailwind doesn’t solve those problems. It just moves the cognitive load from your stylesheet into your HTML.
I spent more time counting gap-4 versus gap-6 in a template than I ever spent writing a single .grid-gap rule in CSS. The speed gain is an illusion that fades after the first day.
When Tailwind Fights Back
Every framework has edge cases. Tailwind has a lot of them.
The Customization Wall
Tailwind works beautifully when your design fits its default scale. The moment you need a custom color or a specific border radius, you hit the tailwind.config.js file. That’s fine for one or two tweaks. But when your designer sends you a complex UI with multiple gradients, custom shadows, and precise spacing that doesn’t match the 4px multiplier, you start writing arbitrary values.
<div class="h-[137px] w-[42%] bg-[#f0f0f0] shadow-[0_4px_12px_rgba(0,0,0,0.15)]">
At this point, you’re writing inline CSS with extra syntax. You’ve lost the consistency that Tailwind promised. And you’re now maintaining two systems: the Tailwind config for standard stuff and inline arbitrary values for everything else. Plain CSS handles custom designs natively. No config file needed.
The Build Step Creep
Tailwind requires a build step. In 2025, that’s common—most projects use Vite or Webpack anyway. But the build step isn’t free. It adds complexity to your CI/CD pipeline, slows down hot reloads on larger projects, and occasionally breaks with version updates.
I had a production build fail because a Tailwind plugin updated and changed how it purges unused classes. The fix took thirty minutes, but that was thirty minutes I could have spent actually building features. Plain CSS has zero build dependencies. It just works.
The Lost Art of Cascade
CSS is a declarative language with a powerful cascade. Tailwind actively works against it.
Specificity Wars
Every utility class in Tailwind has the same specificity. That means the last class in your HTML wins. This leads to ridiculous patterns where you reorder classes to override a previous utility. I’ve seen code like this:
<div class="text-red-500 text-blue-500">This text is blue</div>
The developer added text-blue-500 at the end because a component inherited text-red-500 from a parent. This is not CSS. This is fighting a framework. In plain CSS, you’d write:
.component { color: blue; }
And it would work. The cascade is your friend. Tailwind turns it into an enemy.
Responsive Design Pain
Tailwind’s responsive prefixes (sm:, md:, lg:) are convenient for simple changes. But complex responsive layouts become a nightmare. I once had a card grid that needed three different column counts across four breakpoints. The Tailwind version looked like this:
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
That’s five class names for one property. In plain CSS, it’s five lines in a media query. More importantly, the CSS version groups all layout rules together. You can see the entire responsive strategy at a glance. Tailwind scatters it across your HTML.
A Concrete Anecdote
Last year, I joined a project that had been using Tailwind for eighteen months. The team was proud of their “design system” built entirely from utility classes. When I opened the first component file, I found a 200-line div with over sixty classes. The developer had added classes for months without ever refactoring.
I spent two days trying to understand what that component did. I eventually gave up, deleted the entire file, and rebuilt it in plain CSS with a proper BEM naming convention. The new version had 80 lines of CSS and 30 lines of HTML. It was faster, easier to debug, and the client loved it.
The team was initially skeptical. But after a week, they admitted that plain CSS was simpler to maintain. We migrated the entire codebase over three months. Nobody has asked to go back.
The Practical Takeaway
I’m not saying Tailwind is evil. It works great for small teams, rapid prototypes, and projects where design consistency isn’t critical. But for serious, long-lived websites—especially here in Croatia where many of us build for local businesses that need maintenance over years—plain CSS wins.
Start with CSS Custom Properties (variables) to manage your design tokens. Use a methodology like BEM or CUBE CSS for structure. Write media queries where they belong. Your future self, or whoever inherits your code, will thank you.
The best tool is the one you understand completely. I understand CSS. I never fully understood Tailwind.