TIP
本文档基于Tailwind CSS v4编写, 如有疑问请参考官方文档.
什么是 Tailwind CSS
第一次看到 Tailwind 代码, 大多数人的反应应该都跟我一样: “class 里的这一坨是什么鬼?” 一个<div>上挂十几个类名, 怎么看都不像正经 CSS 的写法. 但真正上手之后, 你就会发现回不去了.
Tailwind CSS 是一个实用优先? 的 CSS 框架. 它并不会给你预制的按钮和卡片等组件, 而是提供一堆很细的工具类, 让你直接在 HTML 里拼出想要的样式.
举个具体的例子: 如果写一个系统通知卡片. 在传统 CSS 中 需要先想类名, 然后再去 CSS 文件里定义:
<div class="notification">
<h2 class="notification-title">部署完成</h2>
<p class="notification-msg">生产环境已更新至 v2.1.0</p>
</div>.notification {
padding: 1.5rem;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.notification-title {
font-size: 1.25rem;
font-weight: 700;
}
.notification-msg {
color: #4b5563;
}而如果你用的是 Tailwind, 同样的效果一行 HTML 搞定:
<div class="p-6 rounded-lg shadow">
<h2 class="text-xl font-bold">部署完成</h2>
<p class="text-gray-600">生产环境已更新至 v2.1.0</p>
</div>渲染效果:
部署完成
生产环境已更新至 v2.1.0
不需要单独建 CSS 文件, 也不需要纠结类名到底要叫.notification还是.notice-card, 样式和结构直接写在一起, 改的时候也不用两个文件来回跳.
安装
v4 的安装体验比 v3 好了太多 — 不用再写tailwind.config.js, 不用配置content路径, 装上就能用. 以 Vite 项目为例:
npm install -D tailwindcss @tailwindcss/vite在vite.config.ts中添加插件:
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [tailwindcss()],
});在 CSS 入口文件中引入 Tailwind:
@import "tailwindcss";最后启动开发服务器, Tailwind 就绑定好了:
npm run devTIP
Tailwind CSS v4 起采用了全新的引擎, 安装方式比 v3 更简洁. 上面的步骤基于 v4. 如果你使用的是 v3, 请参考官方文档.
v4 会自动扫描项目中的模板文件来检测用到的工具类. 但如果你的项目有非标准路径 (比如 Astro 项目中 Markdown 文件里写的 class), 可能需要手动声明扫描范围:
@import "tailwindcss";
@source "../content/**/*.md";核心概念
工具类优先
核心思路: 用预定义的工具类直接描述样式, 而不是先想个类名然后再去定义样式.
<!-- 全屏居中的错误提示 -->
<div class="flex items-center justify-center h-screen">
<p class="text-2xl font-semibold text-red-500">404 - 页面走丢了</p>
</div>每个 class 只做一件事: flex 开启弹性布局, items-center 垂直居中, justify-center 水平居中, h-screen 高度撑满视口.
响应式设计
我觉得 Tailwind 最省心的地方之一就是做响应式布局. 你不需要开一个单独的媒体查询块, 取而代之的是直接在 class 里用断点前缀. 它采用移动优先? 策略, 内置了这些响应式断点?:
| 前缀 | 最小宽度 | 对应场景 |
|---|---|---|
| (无) | 0px | 手机 |
sm | 640px | 大屏手机 |
md | 768px | 平板 |
lg | 1024px | 笔记本 |
xl | 1280px | 桌面显示器 |
2xl | 1536px | 大屏显示器 |
其用法是断点前缀加冒号:
<!-- 手机单列, 平板双列, 桌面三列 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="bg-white p-4 rounded">卡片1</div>
<div class="bg-white p-4 rounded">卡片2</div>
<div class="bg-white p-4 rounded">卡片3</div>
</div>状态变体
在传统 CSS 里, 写个:hover效果就得跑到 CSS 文件里加一条规则. Tailwind 把这些伪类状态也做成了前缀, 这套机制叫状态变体?:
<button class="bg-emerald-500 hover:bg-emerald-600 active:bg-emerald-700 text-white font-medium py-2 px-4 rounded-lg">
确认提交
</button>
<input class="border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 rounded-lg px-3 py-2 outline-none" placeholder="搜索..." />渲染效果 (在上面试试悬停和聚焦):
常用的状态前缀有:
hover:— 鼠标悬停focus:— 获得焦点active:— 点击中disabled:— 禁用态first:/last:— 首个 / 末个子元素dark:— 暗色模式
暗色模式
对暗色模式的支持也是开箱即用的, 只要加个dark:前缀就完事. 本博客就用了 Tailwind 的暗色模式, 你现在看到的页面的背后就是它在工作:
<div class="bg-white dark:bg-gray-900 text-black dark:text-white p-6">
冷知识: 这段内容会自动适配亮色和暗色主题.
</div>渲染效果 (切换页面主题查看):
默认跟随系统prefers-color-scheme设置. v4 中如果需要手动切换 (比如通过 JS toggle), 可以在 CSS 中用@custom-variant定义暗色模式的触发方式:
/* 跟随 .dark 类切换, 而非系统偏好 */
@custom-variant dark (.dark &);常用工具类速查
间距
间距类遵循4px基准制: 数值 x 4px = 实际像素.
<div class="p-4"> <!-- padding: 16px (4x4) -->
<div class="m-2"> <!-- margin: 8px (2x4) -->
<div class="px-6"> <!-- padding-left + right: 24px -->
<div class="mt-8"> <!-- margin-top: 32px -->
<div class="space-y-4"> <!-- 子元素间垂直间距16px -->排版
<p class="text-sm">小字</p> <!-- 14px -->
<p class="text-base">正文</p> <!-- 16px -->
<p class="text-lg">稍大</p> <!-- 18px -->
<p class="text-xl">标题级</p> <!-- 20px -->
<p class="text-2xl">大标题</p> <!-- 24px -->
<p class="font-light">细体</p> <!-- 300 -->
<p class="font-normal">常规</p> <!-- 400 -->
<p class="font-semibold">半粗</p> <!-- 600 -->
<p class="font-bold">粗体</p> <!-- 700 -->
<p class="leading-tight">紧凑行高</p> <!-- 1.25 -->
<p class="leading-relaxed">宽松行高</p> <!-- 1.625 -->颜色
颜色方面, 内置了一整套调色板, 每种颜色有 50 到 950 共 11 个深浅等级:
<p class="text-gray-500">灰色文字</p>
<div class="bg-blue-100">浅蓝背景</div>
<div class="border border-red-300">红色边框</div>数值越小越浅, 越大越深. 500通常是该颜色的” 标准” 色调.
Flexbox 与 Grid
<!-- Flex水平排列, 间距, 垂直居中 -->
<div class="flex items-center gap-4">
<img class="w-12 h-12 rounded-full" src="avatar.png" />
<div>
<p class="font-bold">用户名</p>
<p class="text-gray-500 text-sm">描述文字</p>
</div>
</div>
<!-- Grid三列等宽 -->
<div class="grid grid-cols-3 gap-6">
<div>列1</div>
<div>列2</div>
<div>列3</div>
</div>尺寸
<div class="w-full"> <!-- width: 100% -->
<div class="w-1/2"> <!-- width: 50% -->
<div class="h-screen"> <!-- height: 100vh -->
<div class="max-w-md"> <!-- max-width: 448px -->
<div class="min-h-0"> <!-- min-height: 0 -->
<img class="size-16" /> <!-- width + height: 64px -->过渡与动画
<!-- 悬停放大的标签 -->
<span class="inline-block bg-violet-100 text-violet-700 px-3 py-1 rounded-full text-sm transition-transform duration-200 hover:scale-110">
New
</span>
<!-- 内置动画 -->
<div class="animate-spin w-8 h-8 border-4 border-teal-500 border-t-transparent rounded-full"></div>
<div class="animate-pulse bg-gray-300 h-4 rounded"></div>
<div class="animate-bounce text-2xl">↓</div>渲染效果:
常用的过渡类:
transition/transition-colors/transition-opacity/transition-transform— 指定参与过渡的属性duration-150/duration-300/duration-500— 过渡时长 (毫秒)ease-in/ease-out/ease-in-out— 缓动函数
内置的动画: animate-spin(旋转), animate-ping(脉冲扩散), animate-pulse(呼吸闪烁), animate-bounce(弹跳).
自定义与扩展
任意值
内置工具类覆盖不到的场景, 可以用方括号写任意值:
<div class="w-34.25">精确宽度</div>
<div class="bg-[#1a1a2e]">自定义颜色</div>
<div class="grid-cols-[200px_1fr_200px]">自定义网格</div>
<div class="top-[calc(100vh-80px)]">计算值</div>
<div class="bg-(--my-color)">使用CSS变量</div>主题配置
在 CSS 文件中使用@theme指令扩展设计系统:
@import "tailwindcss";
@theme {
--color-brand: #6366f1;
--font-display: "Inter", sans-serif;
}之后就可以使用text-brand, bg-brand, font-display等工具类.
使用@apply提取组件
如果某组工具类在项目里出现了五六次以上, 每次都复制粘贴一长串 class 确实烦人. 这时候可以用@apply把它们收编成一个 CSS 类:
.tag {
@apply inline-block px-3 py-1 rounded-full text-sm font-medium transition-colors;
}
.tag-info {
@apply tag bg-sky-100 text-sky-700 hover:bg-sky-200;
}
.tag-warn {
@apply tag bg-amber-100 text-amber-700 hover:bg-amber-200;
}WARNING
当然, 不要一上来就@apply所有东西. 否则你又会绕回传统 CSS 的老路. 先想类名, 再定义样式. 只有那些真正在多个文件里反复出现的组合才值得提取, 其他情况直接正常写工具类就好.
实战: 构建一个 Profile 卡片
把上面的知识组合起来 — 就拿这个博客的主页 hero section 做原型, 复刻一个简约版:
<div class="max-w-md mx-auto bg-white dark:bg-gray-800 rounded-xl shadow-lg p-6">
<div class="flex items-center gap-4">
<img
class="w-16 h-16 rounded-full border border-gray-200 dark:border-gray-700 shadow-sm object-cover"
src="/avatar.jpg"
alt="Catluo"
/>
<div>
<h2 class="text-lg font-bold text-gray-900 dark:text-white">Catluo</h2>
<p class="text-sm text-gray-500 dark:text-gray-400">Talk is cheap. Show me the code.</p>
</div>
</div>
<div class="flex flex-wrap gap-2 mt-4">
<span class="px-2 py-0.5 text-xs font-medium border border-gray-200 dark:border-gray-700 rounded-full text-gray-600 dark:text-gray-400">Android</span>
<span class="px-2 py-0.5 text-xs font-medium border border-gray-200 dark:border-gray-700 rounded-full text-gray-600 dark:text-gray-400">C/C++</span>
<span class="px-2 py-0.5 text-xs font-medium border border-gray-200 dark:border-gray-700 rounded-full text-gray-600 dark:text-gray-400">LLVM</span>
<span class="px-2 py-0.5 text-xs font-medium border border-gray-200 dark:border-gray-700 rounded-full text-gray-600 dark:text-gray-400">Reversing</span>
</div>
<div class="flex gap-3 mt-4">
<a href="https://github.com/steveday763" class="text-gray-500 hover:text-gray-900 dark:hover:text-white transition-colors">
GitHub →
</a>
</div>
</div>渲染效果:
在这个卡片中, 我们用到了:
- Flexbox 布局 (
flex,items-center,gap-4,flex-wrap) - 暗色模式 (
dark:bg-gray-800,dark:text-white,dark:border-gray-700) - 状态变体 (
hover:text-gray-900) - 过渡动画 (
transition-colors) - 响应式宽度 (
max-w-md,mx-auto) - 间距与排版 (各种
p-,mt-,text-,font-类)
编辑器配置
VS Code
需要装两个扩展:
- Tailwind CSS IntelliSense — 工具类自动补全、悬停预览实际 CSS、类名排序 (配合 Prettier 插件)
- PostCSS Language Support — 让 VS Code 认识
@apply,@theme,@custom-variant等指令
TIP
如果只装了 Tailwind IntelliSense 没装 PostCSS 插件, VS Code 会对@apply这些 Tailwind 指令标黄, 报” Unknown at rule” 警告. 装上 PostCSS Language Support 就好了.
Prettier
安装官方的 Prettier 插件自动排序 class 属性中的工具类:
npm install -D prettier prettier-plugin-tailwindcss统一的类名顺序能显著提升团队协作时的可读性.
从传统 CSS 迁移所发生的心智转变
如果你写惯了传统 CSS 或 BEM 命名 ?, 第一次打开 Tailwind 项目多半会被一长串 class 吓到 — “这也太丑了吧”. 我当时也是这么想的. 但用了一阵之后, 你会有几个认知上的转变:
再也不用想类名了. 以前每次新建一个组件, 光是纠结叫
.card-wrapper还是.card-container就能浪费好几分钟. 而现在直接用工具类描述样式, 这个心智负担就彻底消失了.样式和结构写在一起, 其实是优势. 改一个组件的时候不用在 HTML 和 CSS 两个文件之间跳来跳去, 所有信息都在眼前.
删代码终于不用提心吊胆了. 传统 CSS 里删一个类名, 你永远不确定别的地方还有没有在用. Tailwind 的工具类是跟着元素走的, 删掉元素, 样式就跟着消失了, 不会留下死代码.
打包体积不是问题. Tailwind 构建时只打包实际用到的工具类, 最终 CSS 通常就几十 KB.
附录: v3 到 v4 迁移踩坑记录
如果你正在从 Tailwind CSS v3 迁移到 v4, 以下是我在实际项目中踩过的坑.
配置迁移对照
v4 采用CSS-first 配置, 不再需要tailwind.config.js:
| v3 (JS 配置) | v4 (CSS 指令) |
|---|---|
tailwind.config.js | 迁移到 CSS (仍可通过@config加载 JS) |
@tailwind base/components/utilities | @import "tailwindcss" |
plugins: [require('@tailwindcss/typography')] | @plugin "@tailwindcss/typography" |
darkMode: ["class"] | @custom-variant dark (.dark &) |
content: ["./src/**/*.{astro,md}"] | @source "../**/*.{astro,md}" |
theme.extend.fontFamily | @theme { --font-sans: ...; } |
踩坑 1: CSS Cascade Layer 优先级
v4 使用原生 CSS Cascade Layers 管理优先级, 层级从低到高:
@layer theme < base < components < utilities如果你在@layer components中写了自定义样式, 它会被@layer utilities中的 typography 插件样式覆盖 — 即使你的选择器更具体.
解决方案: 把需要高优先级的自定义样式放在所有@layer之外 (成为 unlayered 样式), 它们的优先级最高.
踩坑 2: @apply prose展开行为变化
v4 中@apply prose会展开 typography 插件的所有嵌套规则, 把.prose替换为目标选择器, 而不是简单地添加一个类名.
这意味着如果你这样写:
article {
@apply prose;
}v3 生成的 CSS 中, 子元素匹配的是.prose h2, .prose p等. 你的自定义样式.prose .footnotes能正常匹配.
v4 生成的 CSS 中, 子元素匹配的是article h2, article p等. 此时你写的.prose .footnotes就不再匹配了, 因为 HTML 中的<article>元素根本没有prose类.
解决方案: 将所有.prose父选择器改为实际的元素选择器 (如article).
踩坑 3: @custom-variant dark与伪元素不兼容
@custom-variant dark (.dark &)在 v4 中会将选择器包裹在:is()或:where()中. 对于普通元素这没问题, 但对于伪元素 (::marker, ::after, ::before) 会生成无效 CSS:
/* 期望生成 */
.dark article li::marker { color: white; }
/* 实际生成的选择器会将 :where() 拼接到伪元素上, 产生无效CSS */
article li::marker:where(.dark, .dark *) { color: white; } /* 无效! */浏览器会静默丢弃这些无效规则, 导致暗色模式下伪元素样式丢失, 且没有任何报错.
解决方案: 对包含伪元素的选择器, 不使用dark:变体, 而是手动写html.dark祖先选择器:
article li::marker {
@apply text-black/50;
}
/* 手动处理暗色模式 */
html.dark article li::marker {
@apply text-white/75;
}CAUTION
这个问题在构建时和浏览器控制台都不会报错, 只会表现为暗色模式下某些样式” 消失”. 如果你迁移后发现暗色模式下列表标记, checkbox 勾选标记等样式丢失, 大概率是这个原因.
进一步学习
- Tailwind CSS 官方文档 — 最权威的参考, 每个工具类都有示例
- Tailwind Play — 在线试验场, 无需本地安装即可尝试
- Headless UI — Tailwind 官方的无样式组件库, 提供 accessible 的交互组件
NOTE
文章作者: Catluo
文章链接: 快速入门 Tailwind CSS
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 授权协议。
转载请注明来源!