Glittering's blog Glittering's blog
Home
  • 学习手册

    • 《JavaScript教程》
    • 《Git》
    • 《Vite》
    • 《Vue3》
    • 《TypeScript》
    • 《CSS》
    • 《Tailwind CSS》
    • 《ES6 教程》
    • 《TypeScript 从零实现 axios》
  • 技术文档
  • 算法
  • 工作总结
  • 实用技巧
  • collect
About
  • Classification
  • Label
GitHub (opens new window)

Glitz Ma

前端开发工程师
Home
  • 学习手册

    • 《JavaScript教程》
    • 《Git》
    • 《Vite》
    • 《Vue3》
    • 《TypeScript》
    • 《CSS》
    • 《Tailwind CSS》
    • 《ES6 教程》
    • 《TypeScript 从零实现 axios》
  • 技术文档
  • 算法
  • 工作总结
  • 实用技巧
  • collect
About
  • Classification
  • Label
GitHub (opens new window)
  • Tailwind CSS基础知识
  • Tailwind CSS Config
  • Tailwind 插件机制
  • Tailwind 底层生成机制 & purge 原理
    • 一、整体流程总览(先有全局图)
    • 二、Tailwind JIT 是怎么工作的?
      • 1️⃣ 早期(v2 之前)
      • 2️⃣ 现在(v3+,默认 JIT)
      • 核心思想
      • 3️⃣ 内部抽象模型(重要)
      • 每一个 class = 一个「函数调用」
    • 三、content 扫描机制(purge 的核心)
      • 1️⃣ 扫描的是什么?
      • 2️⃣ 关键事实(很多人不知道)
    • 四、为什么动态 class 会被 purge 掉?
      • 原因不是 purge,而是:
    • 五、JIT 的 token 匹配规则(很重要)
      • 合法 token 示例
      • 内部处理顺序
    • 六、variants 是怎么工作的?
      • Tailwind 把 variant 当成「包装器」
    • 七、插件生成的类,为什么不会被 purge?
      • 原因:
    • 八、safelist(白名单)机制
      • 用于:你明确知道要用,但扫描不到
    • 九、为什么 Tailwind 体积还能这么小?
    • 十、Tailwind & Vite 的配合(你会很有共鸣)
      • 为什么 Vite 下 Tailwind HMR 飞快?
    • 十一、常见“诡异 bug”的底层解释
      • 1️⃣ class 写了但没效果
      • 2️⃣ dev 有,build 没有
    • 十二、和你之前 Vue / 编译方向的对照总结
    • 十三、正确使用 Tailwind 的“心法”
  • Tailwind结合 H5 rem/vw 的配置方案
  • H5 Tailwind preset
  • 《Tailwind CSS》
mamingjuan
2025-03-25
目录

Tailwind 底层生成机制 & purge 原理

Tailwind 底层生成机制 & purge 原理,是理解「为什么这样写才安全 / 高效」的关键。

我会按 “从构建 → JIT → purge” 的完整链路给你拆,本文结合 Vite / Vue / 编译原理方向的背景来讲。


# 一、整体流程总览(先有全局图)

Tailwind 构建时大概经历:

tailwind.config.js
        ↓
解析 theme / plugins
        ↓
生成“候选类名规则表”
        ↓
扫描 content(源码)
        ↓
JIT 即时生成 CSS
        ↓
输出最终 CSS
1
2
3
4
5
6
7
8
9
10
11

📌 关键点

  • ❌ 不是预生成所有类
  • ✅ 是 按需生成(JIT)

# 二、Tailwind JIT 是怎么工作的?

# 1️⃣ 早期(v2 之前)

  • 预生成 上万条 CSS
  • 再 purge 没用的
  • 构建慢、CSS 大

# 2️⃣ 现在(v3+,默认 JIT)

# 核心思想

看到一个 class → 立刻生成一条 CSS

例如:

<div class="px-4 text-red-500"></div>
1

JIT 会:

  1. 拆分 class token
  2. 匹配规则
  3. 查 theme 值
  4. 生成 CSS
.px-4 { padding-left: 1rem; padding-right: 1rem }
.text-red-500 { color: #ef4444 }
1
2

# 3️⃣ 内部抽象模型(重要)

# 每一个 class = 一个「函数调用」

text-red-500
│    │    │
│    │    └── scale value
│    └────── theme key
└────────── utility name
1
2
3
4
5

等价于:

text(color = theme.colors.red[500])
1

📌 所以 Tailwind 非常像一个 DSL


# 三、content 扫描机制(purge 的核心)

# 1️⃣ 扫描的是什么?

content: ['./src/**/*.{vue,js,ts,html}']
1

Tailwind 会:

  • 读取文件
  • 用 正则 抽取可能的 class token

例如:

<div class="px-4 text-red-500"></div>
1

会被拆成:

px-4
text-red-500
1
2

# 2️⃣ 关键事实(很多人不知道)

Tailwind 不理解 JS / Vue 语法

它只是扫描“字符串”

📌 所以👇

❌

`bg-${color}-500`
1

扫描结果:

bg-
-color-
-500
1
2
3

👉 匹配失败 → 不生成 CSS


# 四、为什么动态 class 会被 purge 掉?

# 原因不是 purge,而是:

JIT 根本“看不到完整类名”

例如:

<div :class="`bg-${type}-500`"></div>
1

Tailwind 扫描到的只是:

bg-
-type-
-500
1
2
3

所以:

  • 没有合法 token
  • 不会触发生成

# 五、JIT 的 token 匹配规则(很重要)

# 合法 token 示例

bg-red-500
hover:bg-blue-500
md:hover:text-sm
1
2
3

# 内部处理顺序

variants → utility → value
1

例如:

md:hover:bg-red-500
1

等价于:

@media (min-width: 768px) {
  .md\:hover\:bg-red-500:hover { background: ... }
}
1
2
3

# 六、variants 是怎么工作的?

# Tailwind 把 variant 当成「包装器」

hover:   → &:hover
md:      → @media
dark:    → .dark &
1
2
3

所以:

<div class="dark:hover:bg-gray-800"></div>
1

等价于:

.dark .dark\:hover\:bg-gray-800:hover {
  background-color: #1f2937;
}
1
2
3

# 七、插件生成的类,为什么不会被 purge?

# 原因:

插件是在 JIT 之前 注入规则的

plugin
  ↓
addUtilities / addComponents
  ↓
规则表
  ↓
content 扫描
1
2
3
4
5
6
7

📌 插件里的类:

  • 属于「已注册规则」
  • 不需要扫描命中

# 八、safelist(白名单)机制

# 用于:你明确知道要用,但扫描不到

safelist: [
  'bg-red-500',
  'bg-blue-500',
  {
    pattern: /bg-(red|blue|green)-(100|500)/
  }
]
1
2
3
4
5
6
7

📌 慎用

  • safelist = 强制生成
  • 用多了 CSS 会变大

# 九、为什么 Tailwind 体积还能这么小?

因为:

  • 没命中的类 → 根本不生成
  • 没用的 variant → 不会包
  • 插件也是按需生效

一个 Vue 项目:

  • 实际 CSS:10~30KB
  • 而不是 MB 级

# 十、Tailwind & Vite 的配合(你会很有共鸣)

# 为什么 Vite 下 Tailwind HMR 飞快?

文件变更
  ↓
Vite 通知
  ↓
Tailwind 重新扫描这个文件
  ↓
增量生成 CSS
1
2
3
4
5
6
7

📌 不是全量 rebuild

这点和你研究的 Vite 虚拟模块 / HMR 本质一致。


# 十一、常见“诡异 bug”的底层解释

# 1️⃣ class 写了但没效果

  • 拼写不合法
  • theme 中没这个值
  • 被动态拼接

# 2️⃣ dev 有,build 没有

  • content 路径漏了
  • 生产环境 class 写法不同
  • 依赖包里的 class 没被扫描

# 十二、和你之前 Vue / 编译方向的对照总结

Tailwind 编译原理类比
utility AST node
variant wrapper
theme symbol table
JIT on-demand codegen
purge dead code elimination

📌 Tailwind 本质 = CSS 编译器


# 十三、正确使用 Tailwind 的“心法”

  • 1️⃣ 类名 必须是静态字符串
  • 2️⃣ 设计变量 进 theme / plugin
  • 3️⃣ 复杂动态 → 映射表
  • 4️⃣ 公共体系 → 插件
上次更新: 2025/12/26, 01:42:33
Tailwind 插件机制
Tailwind结合 H5 rem/vw 的配置方案

← Tailwind 插件机制 Tailwind结合 H5 rem/vw 的配置方案→

Copyright © 2015-2025 Glitz Ma
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式