正在加载,请稍候…

CSS-in-JS vs Tailwind CSS vs CSS Modules:2026 年对比

比较 2026 年三大 CSS 方案:CSS-in-JS(styled-components、Emotion)、Tailwind CSS 工具类、CSS Mod

CSS-in-JS vs Tailwind CSS vs CSS Modules:2026 年对比

CSS-in-JS vs Tailwind CSS vs CSS Modules:2026 年对比

编写 CSS 的方式会显著影响团队速度、性能和可维护性。2026 年的三种主流方案各有拥趸。以下是客观对比。

三种方案概览

CSS-in-JS vs Tailwind CSS vs CSS Modules: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 ✅ 原生支持

CSS-in-JS vs Tailwind CSS vs CSS Modules:2026 年对比插图

开发者体验

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;
}

如何选择

CSS-in-JS vs Tailwind CSS vs CSS Modules:2026 年对比插图

决策矩阵

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 需要类型安全 + 零运行时的设计系统 简单项目

→ 使用 颜色转换器 工具探索和转换颜色。