/ sagar_pansuriya
§ TailwindCSS

Tailwind CSS: Rethinking Separation of Concerns

Tailwind CSS Cover

The "Inline Styles" Critique

Whenever Tailwind CSS is brought up in developer circles, there's a predictable piece of criticism that almost always surfaces: "Isn't this just inline styles?"

For developers who spent the last decade adhering to strict separation of concerns—keeping HTML cleanly structural and CSS purely stylistic—looking at a Tailwind markup filled with flex items-center justify-between p-4 bg-white rounded-lg shadow-md feels like a massive step backward.

But to understand why Tailwind isn't just inline styles, we first need to look at why we separated CSS from HTML in the first place.

The Traditional Approach: Semantic CSS

In the "old days," the golden rule was separation of concerns. The HTML dictated the structure, and the CSS handled the presentation. You would write semantic class names like .author-bio or .card-container, and define their styles in a separate stylesheet.

<!-- HTML -->
<div class="author-bio">
  <img src="avatar.jpg" class="author-avatar">
  <h3 class="author-name">John Doe</h3>
</div>

/* CSS */
.author-bio {
  display: flex;
  align-items: center;
  padding: 1rem;
  background-color: #fff;
  border-radius: 8px;
}

This felt right. If you needed to redesign the site, you could theoretically just swap out the CSS file and keep the HTML untouched (CSS Zen Garden style).

The Problem with Semantic CSS

However, reality rarely matched the theory. The semantic CSS approach led to several major issues at scale:

  • Naming is Hard: Developers spent too much time agonizing over whether to name a class .sidebar-card or .widget-container.
  • Global Scope: CSS is inherently global. Changing a style for one component often broke another seemingly unrelated component on a different page.
  • Append-Only Style Sheets: Because developers were terrified of breaking existing UI, they rarely deleted CSS. Instead, they appended new styles, causing stylesheets to balloon in size over time.
  • Coupling: Your HTML structure and CSS were tightly coupled anyway. You couldn't just drop a new CSS file on your HTML because the CSS was heavily dependent on the specific DOM structure.

Enter Utility-First CSS

Tailwind flips the script. Instead of creating semantic classes, it provides low-level utility classes that map directly to CSS properties (e.g., pt-4 for padding-top: 1rem, text-center for text-align: center).

<!-- Tailwind -->
<div class="flex items-center p-4 bg-white rounded-lg">
  <img src="avatar.jpg" class="w-12 h-12 rounded-full">
  <h3 class="text-lg font-bold text-gray-900">John Doe</h3>
</div>

Why It's Not Just Inline Styles

So, if we are putting styles back into the HTML, how is this any different from using the style="..." attribute?

1. Magic Numbers vs. Design Systems

With inline styles, you can write style="padding: 13px; color: #43a12b;". This leads to inconsistent UI with hundreds of slightly different shades of colors and spacing values.

Tailwind restricts you to a predefined design system. When you use p-4 and text-blue-500, you are using values pulled directly from a configuration file. This guarantees consistency across your entire application.

2. Media Queries

You cannot write media queries using inline styles. You can't say "make this padding 10px on mobile and 20px on desktop" within a style attribute. With Tailwind, responsive design is built-in. You just write p-2 md:p-4 lg:p-6.

3. States (Hover, Focus, Active)

Similarly, inline styles cannot target pseudo-classes like :hover or :focus. Tailwind handles this gracefully with prefixes like hover:bg-blue-600 or focus:ring-2.

4. Caching and Performance

When you use traditional CSS, every new feature usually means more CSS. With Tailwind, once you've built a few pages, your CSS file stops growing. The utility classes are highly reusable, meaning your generated CSS bundle is tiny and heavily cached by the browser.

Rethinking Separation of Concerns

Tailwind forces us to rethink what we are actually separating. The traditional approach attempted to separate the language (HTML vs CSS). Tailwind argues that the HTML and CSS of a specific UI component are intrinsically linked—they are the same concern.

The true separation of concerns shouldn't be between HTML and CSS files, but rather between components. In a modern JavaScript framework (like React, Vue, or Alpine), the component is the boundary. The structure (HTML), presentation (Tailwind classes), and logic (JS) live together in a single file, neatly encapsulated and isolated from the rest of the application.

Conclusion

Applying composable utility classes to HTML elements isn't a return to the messy days of inline styles. It's the evolution of styling architecture. By providing a constrained design system directly in your markup, Tailwind eliminates naming fatigue, prevents global CSS side effects, and allows you to build user interfaces faster than ever before.

Discussion