DevToolBox免费
博客

Tailwind CSS vs CSS Modules:如何选择?

11 分钟作者 DevToolBox

为你的下一个项目选择 CSS 策略是最重要的架构决策之一。Tailwind CSS 和 CSS Modules 代表了两种根本不同的理念:实用优先的内联样式 vs 组件作用域的传统 CSS。本指南提供深入、实用的对比分析,帮助你根据团队情况、项目规模和技术需求做出正确选择。

什么是 Tailwind CSS?

Tailwind CSS 是一个实用优先的 CSS 框架,提供数千个单一用途的小类名,如 flex、pt-4、text-center 和 rounded-lg。你不需要编写自定义 CSS,而是通过在 HTML 或 JSX 中组合实用类来直接构建设计。框架通过构建时扫描过程只生成项目实际使用的 CSS。

Tailwind 获得广泛采用,因为它完全消除了命名问题。你永远不需要发明类似 .sidebar-inner-wrapper-card-header 的类名。Tailwind v4(2025 年发布)通过基于 Rust 的引擎和零配置设置变得更快。

// Tailwind CSS — React 组件示例
function ProductCard({ product }) {
  return (
    <div className="group relative rounded-2xl border
                    border-gray-200 bg-white p-6 shadow-sm
                    transition-all hover:shadow-xl
                    dark:border-gray-700 dark:bg-gray-800">
      <img src={product.image} alt={product.name}
           className="h-full w-full object-cover
                      group-hover:scale-110" />
      <h3 className="text-lg font-semibold text-gray-900
                     dark:text-white">{product.name}</h3>
      <button className="rounded-lg bg-blue-600 px-4 py-2
                         text-white hover:bg-blue-700">
        Add to Cart
      </button>
    </div>
  );
}

什么是 CSS Modules?

CSS Modules 是一种 CSS 文件约定,其中所有类名默认局部作用于组件。当你导入 CSS Module 文件时,每个类名在构建时会获得唯一的哈希后缀(如 .title 变为 .title_a1b2c3),防止组件之间的样式冲突。CSS Modules 可与纯 CSS、Sass、Less 和 PostCSS 配合使用。

CSS Modules 被 Next.js、Vite、webpack 和大多数现代打包工具原生支持,无需额外配置。它们提供熟悉的 CSS 编写体验,同时解决了全局作用域问题。无论类名如何命名,你的样式都保证不会泄漏到其他组件。

/* ProductCard.module.css */
.card {
  border-radius: 1rem;
  border: 1px solid #e5e7eb;
  background: #ffffff;
  padding: 1.5rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.card:hover {
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
  transform: translateY(-4px);
}

.title {
  font-size: 1.125rem;
  font-weight: 600;
  color: #111827;
}

// ProductCard.tsx
import styles from './ProductCard.module.css';

function ProductCard({ product }) {
  return (
    <div className={styles.card}>
      <h3 className={styles.title}>{product.name}</h3>
    </div>
  );
}

正面对比

此表总结了在实际项目中最重要的维度上的关键差异:

DimensionTailwind CSSCSS Modules
Styling ParadigmUtility-first, inline in JSXComponent-scoped, separate files
Learning CurveLearn utility names (1-2 weeks)Standard CSS (minimal if you know CSS)
Bundle Size8-15KB gzipped (tree-shaken)Grows linearly with components
ScopingGlobal utilities, no conflicts by designAutomatic local hashing
Design SystemBuilt-in via configManual via CSS custom properties
Dark Modedark: prefix modifierCSS custom properties + data attributes
Responsivemd:, lg: prefix modifiersStandard @media queries
IDE SupportExcellent (IntelliSense extension)Good (standard CSS tooling)
SSR CompatibleYes (static CSS)Yes (static CSS)
Migration EffortHigh (rewrite all styles)Low (rename .css to .module.css)

开发者体验

开发者体验是这两种方法差异最大的地方。

Tailwind:通过共置加速开发

Tailwind 将样式和标记放在同一文件中,你永远不需要在 CSS 和 JSX 之间切换上下文。配合编辑器扩展(Tailwind CSS IntelliSense),你可以获得每个实用类的自动补全、颜色值预览和类排序。然而,对于复杂组件,较长的类字符串可能会降低可读性。

CSS Modules:熟悉感和关注点分离

CSS Modules 使用每个 Web 开发者都已经了解的标准 CSS 语法。样式在单独的文件中,让组件专注于逻辑和结构。你可以完全使用 CSS 特性如媒体查询、伪元素和动画,没有任何抽象层。缺点是需要更多的文件切换和发明类名。

性能对比

两种方法在生产环境中都能产生高度优化的输出,但通过不同的机制:

Tailwind CSS: Tailwind 在构建时扫描源文件,只生成你实际使用的实用类的 CSS。典型的 Tailwind 项目产生 8-15KB 的 CSS(gzip 后)。因为实用类在组件间复用,随着应用规模增长,总 CSS 大小增长非常缓慢。
CSS Modules: CSS Modules 的输出取决于你写了多少 CSS。每个组件都有自己的 CSS 块,所以总 CSS 大小与组件数量呈线性增长。但现代打包工具(如 Vite 和 webpack)会执行 CSS tree-shaking 和去重。对大多数应用来说,CSS Modules 产生的包略大于 Tailwind,但差异很少大到影响用户体验。

大规模可维护性

每种方法在拥有众多贡献者的大型代码库中表现如何?

Tailwind: Tailwind 在大型团队中表现出色,因为它通过配置强制执行设计系统。所有间距、颜色、字体大小和断点都来自一个集中的配置文件。开发者不容易引入一次性值,保持了 UI 的一致性。缺点是组件模板可能变得冗长,尤其是带深色模式的复杂响应式布局。
CSS Modules: CSS Modules 提供强隔离性,防止大型代码库中的样式冲突。每个组件都是一个独立单元,保证样式不会泄漏。但 CSS Modules 默认不强制设计系统。没有纪律性,开发者可能引入不一致的间距、颜色和大小。

响应式设计

两种方法都能很好地处理响应式设计,但人体工程学不同:

/* Tailwind — 内联响应式 */
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3
                gap-4 md:gap-6 lg:gap-8">
  ...
</div>

/* CSS Modules — 样式表中的响应式 */
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 768px) {
  .grid { grid-template-columns: repeat(2, 1fr); gap: 1.5rem; }
}
@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(3, 1fr); gap: 2rem; }
}

深色模式实现

深色模式是常见需求,两种方法的处理方式不同:

/* Tailwind — 使用 dark: 前缀 */
<div className="bg-white dark:bg-gray-900
                text-gray-900 dark:text-gray-100">
  ...
</div>

/* CSS Modules — 使用 CSS 自定义属性 */
:root { --bg-primary: #ffffff; --text-primary: #111827; }
[data-theme="dark"] { --bg-primary: #111827; --text-primary: #f9fafb; }

.container { background: var(--bg-primary); color: var(--text-primary); }

何时选择 Tailwind CSS

  • 快速原型开发和 MVP,开发速度是首要优先级。
  • 希望从第一天起就有内置设计系统(一致的间距、颜色和排版)的团队。
  • 设计师和开发者紧密合作且使用相同设计令牌的项目。
  • 组件密集型应用(React、Vue、Svelte),其中样式自然与标记共置。
  • 希望最小化 CSS 文件管理并完全避免命名约定的团队。
  • 具有大量响应式和深色模式需求的项目,Tailwind 的修饰符(md:、dark:、hover:)能减少样板代码。

何时选择 CSS Modules

  • 拥有强 CSS 专业知识、偏好使用完整 CSS 能力编写传统样式表的团队。
  • 需要复杂 CSS 特性(如动画、伪元素、容器查询和 CSS 网格布局)的项目,这些特性受益于专门的样式表文件。
  • 样式隔离至关重要的大型代码库,你需要保证样式不泄漏且无运行时开销。
  • 从遗留 CSS 代码库逐步迁移,因为 CSS Modules 允许与现有全局样式并存地渐进采用。
  • 优先考虑干净、可读的 JSX 模板而非共置样式的应用。
  • 使用服务端渲染(SSR)的项目,偏好零 JavaScript CSS 方案以提高性能。

混合方案

许多成功的团队在同一项目中同时使用 Tailwind 和 CSS Modules。Tailwind 处理布局、间距和实用样式,而 CSS Modules 处理复杂的组件特定样式(如动画和复杂的悬停效果)。

// 混合方案:Tailwind 做布局 + CSS Module 做复杂样式
import styles from './AnimatedCard.module.css';

function AnimatedCard({ front, back }) {
  return (
    <div className={`${styles.card} w-64 h-80`}>
      <div className={styles.inner}>
        <div className={`${styles.front} rounded-xl bg-white
                         shadow-lg p-6`}>
          {front}
        </div>
        <div className={`${styles.back} rounded-xl bg-blue-600
                         text-white p-6`}>
          {back}
        </div>
      </div>
    </div>
  );
}

最佳实践

  • Tailwind:将重复的类模式提取到可复用的 React 组件中,而非 @apply 指令。在组件框架中,组件本身就是抽象层。
  • Tailwind:使用 Prettier 插件(prettier-plugin-tailwindcss)自动按一致顺序排序类名,使类字符串更易阅读和审查。
  • CSS Modules:使用 CSS 自定义属性(设计令牌)来定义颜色、间距和排版,在没有框架的情况下保持组件间的一致性。
  • CSS Modules:使用 composes 关键字在模块之间共享通用样式,避免重复同时保持作用域。
  • 两者:设置代码检查。Tailwind 用 eslint-plugin-tailwindcss,CSS Modules 用 stylelint,尽早发现错误并强制执行规范。
  • 两者:测量生产环境的 CSS 包大小。使用 Lighthouse 或 webpack-bundle-analyzer 等工具确保你的 CSS 策略不会产生不必要的大负载。

试试我们相关的开发者工具

FAQ

可以同时使用 Tailwind CSS 和 CSS Modules 吗?

可以,它们在同一项目中配合良好。Next.js 和 Vite 开箱即用地支持两者。常见模式是使用 Tailwind 处理布局和间距实用类,使用 CSS Modules 处理复杂的组件样式(如动画、伪元素或复杂的悬停效果)。导入 CSS Module 并在 className 中将其类与 Tailwind 实用类组合使用。

Tailwind CSS 的包体积比 CSS Modules 大吗?

通常恰恰相反。Tailwind 扫描代码只生成实际使用的实用类的 CSS。典型项目产生 8-15KB CSS(gzip 后)。CSS Modules 的输出随组件数量和唯一样式线性增长。对于大型应用,Tailwind 通常产生更小的 CSS 包,因为实用类在组件间共享。

Tailwind CSS 比 CSS Modules 更难维护吗?

取决于你的方法。长 Tailwind 类字符串可能降低可读性,但通过将其提取到 React 组件中可以缓解。CSS Modules 初始可读性更好,但需要纪律来保持一致性。两种方法在有适当规范和工具的情况下都可以大规模维护。

Tailwind CSS 能与 Next.js 的服务端组件配合使用吗?

可以。Tailwind CSS 纯粹是编译时的,生成静态 CSS。它与 React Server Components 完美配合,因为不添加任何客户端 JavaScript。CSS Modules 出于同样原因也能与服务端组件无缝配合。

使用 Tailwind 之前需要先学 CSS 吗?

是的,即使使用 Tailwind,理解 CSS 基础也至关重要。Tailwind 实用类直接映射到 CSS 属性(flex 映射到 display: flex,p-4 映射到 padding: 1rem)。不理解底层 CSS,你将难以调试布局问题、理解响应式断点或构建复杂布局。先学 CSS,然后将 Tailwind 作为在此知识之上的生产力工具。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

TWCSS to Tailwind

相关文章

Tailwind CSS 速查表:完整类名参考指南

最全面的 Tailwind CSS 速查手册,按类别整理所有工具类。间距、颜色、排版、Flexbox、Grid 等快速参考。

CSS Flexbox 完全指南:所有属性与布局模式详解

掌握 CSS Flexbox:完整的容器和项目属性指南、可视化示例,以及导航栏、卡片网格、圣杯布局等实际布局模式。