Tailwind CSS thắng cuộc đua CSS frontend 2024-2026 — Next.js, Vercel, Shopify, Adobe đều ship Tailwind production. Bài này phân tích pros/cons thực tế, khi nào tốt, khi nào không.
Vì sao Tailwind thắng?
- RSC compatibility — không runtime cost
- Bundle nhỏ sau tree-shake (atomic class)
- Design token-driven qua config
- Ecosystem khổng lồ: shadcn/ui, Radix, Headless UI
- JIT compile nhanh, arbitrary value
w-[437px]
Khi nào Tailwind tốt?
1. Project Next.js / React modern
RSC không thân thiện với CSS-in-JS runtime. Tailwind chạy hoàn toàn build-time → no JS overhead, server render OK.
2. Team ship nhanh
<div className="flex items-center gap-3 p-4 rounded-lg border border-gray-200 hover:bg-gray-50">
<Avatar />
<div className="flex-1 min-w-0">
<p className="font-semibold truncate">An Nguyen</p>
<p className="text-sm text-gray-500">an@example.com</p>
</div>
</div>
Không jump file, không nghĩ class name. Refactor: xoá element = xoá CSS đi kèm.
3. Design system token-based
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
brand: { 50: '#eff6ff', 500: '#3b82f6', 600: '#2563eb' },
ink: { 900: '#111827', 950: '#030712' },
},
spacing: { '18': '4.5rem' },
fontFamily: { sans: ['Inter', 'sans-serif'] },
},
},
}
Class bg-brand-500, text-ink-900 consistent toàn app. Đổi value config → cập nhật khắp nơi.
4. shadcn/ui ecosystem
shadcn copy/paste component code thay vì npm install — anh control hoàn toàn. 40+ component accessible, beautiful, tweak được. De-facto cho React 2026.
Khi nào KHÔNG dùng Tailwind?
1. Content site thuần (Hugo, Jekyll, blog static)
Đơn giản hơn dùng vanilla CSS. Tailwind cần build pipeline — overkill cho 5 page.
2. Team không có build tool quen thuộc
Email template HTML, app legacy không có bundler — Tailwind khó setup. Vanilla CSS đơn giản hơn.
3. Component library publish ra ngoài
Consumer chưa chắc dùng Tailwind. Nên dùng CSS Modules hoặc Vanilla Extract — bundle CSS độc lập.
4. App đã invest sâu CSS-in-JS
Migration cost cao. Trừ khi gặp vấn đề RSC, giữ nguyên.
Anti-pattern phổ biến
// ❌ Duplicate utility everywhere
<button className="px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-700 text-white font-semibold">Save</button>
// ... 50 button khác cùng class chains
// ✓ Extract component với cva
import { Button } from '@/components/ui/button'
<Button variant="primary">Save</Button>
// ❌ Inline arbitrary mọi giá trị
<div className="w-[437px] h-[219px] mt-[13px]">...</div>
// ✓ Define trong theme nếu reuse, hoặc round to scale
<div className="w-md h-52 mt-3">...</div>
Config quan trọng nhất
// tailwind.config.ts
import type { Config } from 'tailwindcss'
export default {
content: [
'./src/**/*.{ts,tsx}',
'./node_modules/@your-design-system/**/*.js', // include external lib
],
darkMode: 'class', // toggle qua <html class="dark">
theme: {
extend: {
colors: { /* design token */ },
animation: {
'fade-in': 'fadeIn 0.3s ease-out',
},
keyframes: {
fadeIn: { from: { opacity: '0' }, to: { opacity: '1' } },
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
} satisfies Config
Dark mode
<div className="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
<p className="text-gray-500 dark:text-gray-400">Subtle text</p>
</div>
Dùng next-themes hoặc useTheme hook để toggle class trên <html>.
Kết luận
Tailwind CSS hợp 80% project React/Next.js mới. Đầu tư 1-2 ngày học + setup component layer (cva, shadcn) → ship nhanh, bundle nhỏ, refactor dễ. Đọc thêm CSS architecture so sánh để cân nhắc với BEM/CSS-in-JS, và React Server Components để hiểu vì sao Tailwind thắng cho RSC.