Tailwind
Utility-first CSS。
Tailwind CSS:原子化样式实战
这一课你将能做到
- 用 Tailwind 工具类直接写出常见布局、间距、颜色、字体样式
- 配置响应式前缀(sm/md/lg)和 dark 模式,一套代码适配多设备
- 自定义配置文件扩展主题,用
@apply 提取重复样式
为什么要学
传统 CSS 写样式,你需要在 HTML 和 CSS 文件之间来回切换,想一个语义化的类名,然后写一堆规则。Tailwind 的思路完全相反:直接在 HTML 里写原子化工具类,一个类只干一件事(比如 p-4 就是 padding 1rem)。样式即结构,所见即所得。
Tailwind 是目前增长最快的 CSS 框架,被 Vercel、GitHub、OpenAI 等公司采用。它的优势是:不用想类名、样式不冲突、响应式极简、最终 CSS 体积比手写还小(自动 tree-shaking)。
先建立图像
传统 CSS vs Tailwind 的对比:
<!-- 传统 CSS -->
<div class="card">
<h2 class="card-title">标题</h2>
</div>
<style>
.card { padding: 1.5rem; background: white; border-radius: 0.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.card-title { font-size: 1.25rem; font-weight: 600; color: #1f2937; }
</style>
<!-- Tailwind -->
<div class="p-6 bg-white rounded-lg shadow-sm">
<h2 class="text-xl font-semibold text-gray-800">标题</h2>
</div>
Tailwind 把样式内联到 HTML,减少了上下文切换,也避免了「这个类名被谁用了」的困惑。
跟着做
步骤 1:安装与配置
用 Vite + React 项目演示:
npm create vite@latest my-tailwind-app -- --template react
cd my-tailwind-app
npm install
# 安装 Tailwind v4(当前最新)
npm install tailwindcss @tailwindcss/vite
配置 Vite(vite.config.js):
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [react(), tailwindcss()]
});
在 src/index.css 中引入:
@import "tailwindcss";
启动项目:
npm run dev
现在可以在 JSX 里直接用 Tailwind 类了。
步骤 2:基础工具类
function App() {
return (
<div className="min-h-screen bg-gray-100 p-8">
{/* 卡片容器 */}
<div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden">
{/* 内边距、文字居中 */}
<div className="p-6 text-center">
{/* 标题:大字号、粗体、深灰色 */}
<h1 className="text-2xl font-bold text-gray-900 mb-2">
Tailwind 入门
</h1>
{/* 段落:灰色、行高 */}
<p className="text-gray-600 leading-relaxed">
用工具类快速构建界面,不用写一行 CSS。
</p>
{/* 按钮:内边距、背景色、圆角、悬停效果 */}
<button className="mt-4 px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors">
开始使用
</button>
</div>
</div>
</div>
);
}
| 类别 | 示例 | 含义 |
|---|
| 间距 | p-4 m-2 px-6 py-3 | padding/margin,4=1rem |
| 尺寸 | w-full h-64 max-w-md | 宽、高、最大宽度 |
| 布局 | flex grid block hidden | display 属性 |
| 对齐 | items-center justify-between | flex/grid 对齐 |
| 颜色 | bg-blue-500 text-gray-800 | 背景、文字颜色 |
| 字体 | text-lg font-bold text-center | 字号、字重、对齐 |
| 边框 | rounded-lg border border-gray-300 | 圆角、边框 |
| 阴影 | shadow-sm shadow-lg | 投影 |
步骤 3:响应式前缀
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="bg-white p-4 rounded-lg">卡片 1</div>
<div className="bg-white p-4 rounded-lg">卡片 2</div>
<div className="bg-white p-4 rounded-lg">卡片 3</div>
</div>
grid-cols-1:默认(手机)一列
md:grid-cols-2:768px 以上两列
lg:grid-cols-3:1024px 以上三列
| 前缀 | 最小宽度 | 设备 |
|---|
| 无 | 0px | 手机 |
sm: | 640px | 大手机 |
md: | 768px | 平板 |
lg: | 1024px | 小桌面 |
xl: | 1280px | 桌面 |
2xl: | 1536px | 大桌面 |
步骤 4:悬停、聚焦等状态
<button className="
px-4 py-2
bg-blue-500 text-white
rounded-lg
hover:bg-blue-600
focus:outline-none focus:ring-2 focus:ring-blue-300
active:bg-blue-700
disabled:opacity-50 disabled:cursor-not-allowed
transition-all
">
提交
</button>
<input className="
w-full px-3 py-2
border border-gray-300 rounded-md
placeholder-gray-400
focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500
" placeholder="请输入..." />
状态前缀:hover:、focus:、active:、disabled:、visited:。
步骤 5:Dark 模式
Tailwind 支持 dark: 前缀,配合 class 策略切换:
// 在 html 标签上切换 class="dark"
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
<h1 className="text-2xl font-bold">标题</h1>
<p className="text-gray-600 dark:text-gray-300">内容</p>
</div>
启用 dark 模式:Tailwind v4 默认使用系统偏好,如需手动切换,在 CSS 中配置:
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
然后 JS 控制 document.documentElement.classList.toggle("dark")。
步骤 6:自定义配置与 @apply
Tailwind v4 用 CSS 配置主题,不再需要 tailwind.config.js:
@import "tailwindcss";
@theme {
--color-brand: #6366f1;
--font-display: "Inter", sans-serif;
}
然后使用:bg-brand、font-display。
@layer components {
.btn-primary {
@apply px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors;
}
}
但注意:官方推荐优先用组件抽象(React 组件),而不是 @apply,后者只用于真正无法组件化的场景。
讲清楚要点
- 原子化是 Tailwind 的核心:一个类只做一个 CSS 声明,
p-4 就是 padding 1rem,text-red-500 就是文字红色。组合使用,不冲突。
- 移动优先的响应式:默认样式针对手机,
md:、lg: 等前缀向上覆盖。不要写 max-width 媒体查询。
- 设计约束带来一致性:Tailwind 的间距、颜色、字号都是预设的刻度(4 的倍数),避免了「这个 padding 用 13px 还是 15px」的随意性。
- 生产环境自动优化:构建时 Tailwind 扫描所有文件,只生成用到的类,最终 CSS 通常只有 10KB 左右。
- 组件化优于 @apply:在 React/Vue 中,重复的样式应该抽象成组件,而不是用 @apply 提取 CSS 类。后者是逃生舱,不是首选。
你可能会懵的地方
-
Tailwind 和内联样式有什么区别?
内联样式优先级最高、无法写伪类和媒体查询;Tailwind 是真实的 CSS 类,支持 hover、focus、响应式,且可以 tree-shaking。
-
类名会不会太长,HTML 很乱?
确实比传统 CSS 的类名长,但换来了开发效率和可预测性。配合编辑器的 Tailwind 插件(自动补全、悬停预览),体验很好。
-
Tailwind 和 Bootstrap 有什么区别?
Bootstrap 是组件库(提供现成的按钮、卡片样式);Tailwind 是工具库(只提供原子类,组件自己搭)。Tailwind 更灵活,不会「看起来像 Bootstrap」。
-
v3 和 v4 有什么区别?
v4 是 2025 年的大版本:用 CSS 代替 JS 配置文件、用 Vite 插件代替 PostCSS、性能大幅提升。新项目直接用 v4。
-
Tailwind 能完全替代 CSS 吗?
90% 的场景可以。复杂动画、伪元素内容、特定选择器仍需写自定义 CSS,但量极少。
错法对照
| 错法 | 问题 | 正解 |
|---|
| 每个元素都写一长串类 | 难以维护 | 抽象成 React/Vue 组件 |
滥用 @apply 提取类 | 失去原子化优势,回到传统 CSS | 优先组件化,@apply 只用于无组件场景 |
| 在 Tailwind 里写任意值 | p-[13px] 破坏设计系统 | 尽量用预设刻度,或扩展 theme |
响应式写 max-width | 与移动优先理念冲突 | 用 md:、lg: 前缀 |
| 忽略 dark 模式 | 后期补做成本高 | 一开始就写 dark: 前缀 |
| 生产环境类名没生效 | 构建时 tree-shaking 掉了动态类 | 避免 class="text-${color}",用完整类名或 safelist |
| 引入整个 Tailwind CDN 到生产 | 体积巨大,无优化 | 用构建工具(Vite/PostCSS) |
卡点急救
- 类名写了但样式没生效:检查类名拼写;检查是否在
content 扫描范围内;检查是否有更具体的样式覆盖;F12 看元素是否真有这个类。
- 响应式不生效:确认前缀写法正确(
md: 不是 md-);确认视口 meta 标签已设置。
- 动态类名不生效:Tailwind 扫描的是源码文本,
text-${color} 这种动态拼接不会被扫描到。解决:写完整类名映射,或在 CSS 中用 @source inline() safelist。
- Dark 模式不切换:确认切换的是
html 或 body 上的 dark 类;确认 CSS 中配置了 @custom-variant。
面试常问
-
Tailwind 的优点和缺点?
优点:开发快、一致性高、响应式极简、生产体积小。缺点:HTML 类名冗长、学习曲线(要记类名)、复杂动画仍需手写 CSS。
-
Tailwind 如何实现 tree-shaking?
构建时扫描所有源文件,提取实际用到的类名,只生成这些类的 CSS。所以最终产物极小。
-
Tailwind 的设计理念是什么?
原子化 CSS + 设计约束。通过提供受限的、一致的设计刻度,避免随意值,让团队协作时 UI 更统一。
-
怎么处理重复的长类名?
官方推荐组件化(React/Vue 组件)。次选是提取为模板片段。最后才是 @apply。
自测三问
- 用 Tailwind 写一个按钮:蓝色背景、白色文字、圆角、悬停时颜色加深。
- 解释
md:grid-cols-2 的含义,以及它和 @media (max-width: 768px) 的区别。
- 为什么官方推荐用 React 组件而不是
@apply 来复用样式?
小结一句话
Tailwind 把 CSS 变成积木:原子类是砖块,响应式前缀是图纸,组件是房间——不用写一行 CSS 文件,就能搭出现代、一致、响应式的界面。
延伸