
CSS-in-JS vs Tailwind CSS vs CSS Modules:2026 年对比
编写 CSS 的方式会显著影响团队速度、性能和可维护性。2026 年的三种主流方案各有拥趸。以下是客观对比。
三种方案概览
CSS Modules
/* Button.module.css */
.button {
padding: 0.5rem 1rem;
background: #3b82f6;
color: white;
border-radius: 0.375rem;
border: none;
cursor: pointer;
}
.button:hover {
background: #2563eb;
}
.large {
padding: 0.75rem 1.5rem;
font-size: 1.125rem;
}
import styles from './Button.module.css';
export function Button({ size = 'default', children, ...props }) {
return (
<button
className={`${styles.button} ${size === 'large' ? styles.large : ''}`}
{...props}
>
{children}
</button>
);
}
CSS-in-JS (styled-components)
import styled, { css } from 'styled-components';
const Button = styled.button<{ $size?: 'default' | 'large' }>`
padding: 0.5rem 1rem;
background: #3b82f6;
color: white;
border-radius: 0.375rem;
border: none;
cursor: pointer;
&:hover {
background: #2563eb;
}
${props => props.$size === 'large' && css`
padding: 0.75rem 1.5rem;
font-size: 1.125rem;
`}
`;
// 使用
<Button $size="large">Click me</Button>
Tailwind CSS
export function Button({ size = 'default', children, ...props }) {
const sizeClasses = size === 'large'
? 'px-6 py-3 text-lg'
: 'px-4 py-2';
return (
<button
className={`${sizeClasses} bg-blue-500 hover:bg-blue-600 text-white rounded-md border-none cursor-pointer`}
{...props}
>
{children}
</button>
);
}
性能对比
打包体积影响
CSS Modules:
运行时开销:无(纯 CSS,构建时编译)
打包体积:0 JS 开销
Tailwind CSS:
运行时开销:无(清除未使用 CSS,无 JS)
打包体积:约 5-20KB CSS(清除未使用类后)
CSS-in-JS (styled-components):
运行时开销:约 50KB JS(styled-components 库)
运行时:样式在运行时注入 → 额外 JS 执行
CSS-in-JS (vanilla-extract, 零运行时):
运行时开销:无(构建时编译为 CSS)
打包体积:小 CSS 文件
服务端渲染 (SSR)
| 方案 | SSR 复杂度 |
|---|---|
| CSS Modules | ✅ 原生支持 |
| Tailwind CSS | ✅ 原生支持 |
| styled-components | ⚠️ 需要 ServerStyleSheet 设置 |
| Emotion | ⚠️ 需要 cache 设置 |
| vanilla-extract | ✅ 原生支持 |
开发者体验
Tailwind CSS — 优点
// ✅ 无需在文件间切换上下文
// ✅ 内置设计约束(间距比例、颜色)
// ✅ 响应式设计内联:sm:、md:、lg:
// ✅ 暗色模式内联:dark:
// ✅ 无需命名!
<div className="flex items-center gap-4 p-6 bg-white dark:bg-gray-800 rounded-xl shadow-md">
<img className="w-12 h-12 rounded-full" src={avatar} />
<div>
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{name}</h2>
<p className="text-gray-500 dark:text-gray-300 text-sm">{role}</p>
</div>
</div>
Tailwind CSS — 缺点
// ❌ 长类字符串难以阅读
<button className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2">
Click
</button>
// 解决方案:提取为组件或使用 cn() 工具函数
CSS-in-JS (styled-components) — 优点
// ✅ 利用 JavaScript 全部能力实现动态样式
const Progress = styled.div<{ $percent: number; $color: string }>`
width: ${props => props.$percent}%;
background: ${props => props.$color};
height: 8px;
border-radius: 4px;
transition: width 0.3s ease;
`;
// ✅ 主题化自然
<ThemeProvider theme={{ primaryColor: '#3b82f6', spacing: 4 }}>
<App />
</ThemeProvider>
CSS Modules — 优点
/* ✅ 常规 CSS — 无需学习新语法 */
/* ✅ 兼容任何 CSS 预处理器(SCSS、PostCSS) */
/* ✅ 零运行时开销 */
/* ✅ 类名自动局部作用域 */
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
如何选择
决策矩阵
Q1:这是新项目吗?
是 → 考虑 Tailwind CSS(2026 年行业趋势)
否 → 坚持现有方案(迁移成本高)
Q2:团队熟悉 Tailwind 吗?
是 → Tailwind CSS
否 → CSS Modules(熟悉,学习曲线低)
Q3:需要大量动态样式吗?
是 → CSS-in-JS(styled-components、Emotion)
否 → Tailwind 或 CSS Modules
Q4:SSR/性能是否关键?
是 → CSS Modules 或 Tailwind(无运行时开销)
或 vanilla-extract(零运行时 CSS-in-JS)
否 → 任何方案均可
Q5:是否使用组件库(shadcn/ui 等)?
是 → Tailwind(大多数组件库面向 Tailwind)
否 → 自行选择
团队规模考量
独立开发者/小团队:
→ Tailwind CSS(构建最快,开发者体验好)
拥有设计系统的大团队:
→ CSS Modules + 设计令牌
→ 或 styled-components + ThemeProvider
严格模式的企业:
→ CSS Modules(严格、熟悉、无魔法)
→ 或 vanilla-extract(类型安全、零运行时)
并排实践示例
卡片组件
Tailwind:
function Card({ title, description, image }) {
return (
<div className="rounded-xl overflow-hidden shadow-lg bg-white hover:shadow-xl transition-shadow">
<img className="w-full h-48 object-cover" src={image} />
<div className="p-6">
<h3 className="text-xl font-bold mb-2">{title}</h3>
<p className="text-gray-600">{description}</p>
</div>
</div>
);
}
CSS Modules:
// Card.module.css
.card { border-radius: 12px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
.card:hover { box-shadow: 0 10px 25px rgba(0,0,0,0.15); }
.image { width: 100%; height: 192px; object-fit: cover; }
.body { padding: 24px; }
.title { font-size: 1.25rem; font-weight: 700; margin-bottom: 8px; }
.description { color: #4b5563; }
// Card.tsx
import s from './Card.module.css';
function Card({ title, description, image }) {
return (
<div className={s.card}>
<img className={s.image} src={image} />
<div className={s.body}>
<h3 className={s.title}>{title}</h3>
<p className={s.description}>{description}</p>
</div>
</div>
);
}
2026 年格局
当前采用趋势:
- Tailwind CSS — 在新项目中占主导,尤其与 React/Next.js 搭配
- CSS Modules — 稳定,在 Vue 和服务端框架中流行
- styled-components/Emotion — 下降,但仍用于现有代码库
- vanilla-extract — 增长,尤其在设计系统中
- PandaCSS/StyleX — 新兴的零运行时替代方案
总结
| 方案 | 最适合 | 应避免的情况 |
|---|---|---|
| Tailwind CSS | 新项目、快速原型、有设计系统的团队 | 需要支持 IE11 的旧浏览器 |
| CSS Modules | Vue 项目、偏好纯 CSS 的团队、SSR 应用 | 需要大量动态样式 |
| styled-components | 现有 React 代码库、复杂主题化 | 性能关键、SSR 场景 |
| vanilla-extract | 需要类型安全 + 零运行时的设计系统 | 简单项目 |
→ 使用 颜色转换器 工具探索和转换颜色。