1. 起因
项目从 SCSS 迁到 Tailwind 有一阵子了,一开始觉得”不就是把 class 名换一下”,结果动态拼类名、生产环境样式丢失这几个问题接连遇到,记一下踩过的坑。
2. 动态拼接的类名不会被打包进去
这是最容易踩、也是踩了之后最摸不着头脑的一个坑:
1 | function Badge({ color }) { |
本地开发时(如果用了 JIT 全量扫描或者刚好命中过这个类名)可能看起来是好的,但打包到生产环境后颜色直接消失,bg-red-500 变成了没有任何样式的空 class。原因是 Tailwind 是靠静态扫描源码文本来决定生成哪些 class 的,它并不会执行你的 JS 代码,bg-${color}-500 这种拼接字符串在扫描阶段根本不是一个完整的、能匹配到的 class 名,Tailwind 找不到就不会把对应的 CSS 生成出来。
解法是把可能用到的完整类名都以字面量的形式写在代码里,让扫描器能扫到:
1 | const colorMap = { |
这条规则在官方文档里其实写得很清楚,但第一次踩到之前基本没人会认真看这一段,都是吃了亏之后回去翻文档才恍然大悟。
3. content 配置路径没扫全,样式在生产环境丢失
1 | // tailwind.config.js |
跟上一条类似,但原因不同:项目里如果同时有 .js 和 .tsx 文件,content 配置里只写了 .js,那 .tsx 文件里用到的所有 class 在生产构建时都不会被扫描到,本地开发环境如果开了某种兜底扫描或者缓存了一份旧的产物,可能还看不出问题,一到生产构建就大面积丢样式。这类问题最烦的地方是它不会报错,只是安安静静地不生成对应 CSS,界面上看到的是”这个元素没有预期的样式”,容易被误以为是拼错了类名而不是配置问题。
排查思路:怀疑是这个问题的话,先去确认 content 数组是不是覆盖了项目里所有会用到 Tailwind class 的文件类型和目录,包括一些容易被忘记的地方,比如从 node_modules 里引入的自己维护的组件库、或者 .mdx 文件。
4. @apply 用多了,等于把 Tailwind 用成了普通 CSS
1 | .btn-primary { |
@apply 本身没问题,用来抽取真正高频重复、跨很多组件共用的样式组合是合理的。但见过有的项目为了”看起来更整洁”,把几乎每个组件的 class 都用 @apply 抽成了一个语义化的 CSS 类名,这样写到最后跟直接写传统 CSS 没有本质区别,Tailwind 本来的优势——在 HTML/JSX 里直接看到样式、不用来回切文件——反而被架空了。个人现在的判断标准是:只有当某个样式组合在 3 个以上完全不相关的地方重复出现时,才考虑用 @apply 抽出来,其余情况就老老实实在 class 里堆工具类。
5. 暗色模式类名忘了在 html 标签上切换策略
1 | // tailwind.config.js |
darkMode 默认是 'media',跟着系统的 prefers-color-scheme 走。项目里要做一个手动切换的深色模式开关,配置改成了 'class',但忘了在切换逻辑里真正去操作 document.documentElement.classList,导致写好的一堆 dark:bg-gray-900 完全不生效——配置改对了,但触发条件没接上,两头都以为是对方的问题,排查的时候容易走弯路。
1 | function toggleDarkMode() { |
6. 小结
Tailwind 踩的坑基本都指向同一个根源:它是靠静态扫描源码文本来生成 CSS 的,不是运行时按需生成。凡是涉及动态拼接类名、content 路径没扫全、暗色模式类名依赖的触发条件没接上,本质上都是”Tailwind 没扫描到这个 class 因此没生成对应样式”,排查这类问题先往这个方向想,比一个个 class 去对样式表快得多。