Tailwind 默认不生成 BEM 类名,需在 tailwind.config.js 的 safelist 中配置正则(如 /^[a-z]+(__|--)[a-z]+$/)保留 BEM 模式,否则 PurgeCSS 会删除未识别的类;BEM 类应专注结构语义,样式由 Tailwind 原子类承担。

Tailwind 默认不生成 BEM 类名,直接写 card__header 或 button--primary 不会生效——这不是 bug,是设计使然。必须主动配置,否则这些类名在构建后被 PurgeCSS 删光。
为什么 HTML 里写了 BEM 类却没样式?
根本原因是 Tailwind 的 content 扫描器只识别原子类(如 px-4、text-blue-500),对 card__body 这种含双下划线或双短横的命名完全忽略。它不会为你生成对应 CSS 规则,DevTools 里自然查不到匹配项。
- 常见错误现象:
class="card__footer"在浏览器里无任何样式,检查元素发现该 class 名根本没出现在<style></style>中 - 启用
purge: true(或现代content配置)后,未显式声明的 BEM 类全被清除 - 团队成员按 BEM 文档写类名,但 CI 构建后样式丢失,排查半天才发现是扫描器漏掉了
必须加 safelist 正则,否则 BEM 类被 PurgeCSS 删除
在 tailwind.config.js 的 safelist 里用正则显式保留 BEM 模式,这是最轻量也最可靠的方案。不要试图“禁用 PurgeCSS”或把所有 BEM 类手动列出来——项目一复杂就维护不住。
- 推荐写法:
/^[a-z]+(__|--)[a-z]+$/—— 匹配形如card__header、form--disabled的标准 BEM 类 - 若 block 名有固定前缀(如只用
user-开头),可收紧为/^user-[a-z]+(__|--)[a-z]+$/ - 注意:正则必须写在
safelist数组里,不是theme.extend下;且需确保正则能覆盖所有实际使用的 BEM 变体(比如带数字的step__item-2就得额外加/^step__item-\d+$/) - 别漏掉
container这类常见 block 名——如果项目里用了container__sidebar,而tailwind.config.js里又定义了theme.extend.container,PurgeCSS 可能误判并删掉整个container块,得在 safelist 里补上/^container(__|--)*/
@layer components + @apply 是语义模拟,不是类名替代
如果你希望 BEM 类名承载结构意图(比如 card__header 表示“卡片头部区域”),而不是单纯为了样式复用,那就该用 @layer components 把 BEM 类和 Tailwind 原子类绑定起来。这本质是把 BEM 当作组件 API 接口,而非样式容器。
立即学习“前端免费学习笔记(深入)”;
- 必须写在
@layer components块内,否则会被 PurgeCSS 当作未使用类删除 - 示例:
@layer components { .card__header { @apply px-6 py-4 bg-white border-b border-gray-100; } .card--featured { @apply border-blue-500 shadow-md; } } - 禁止在
@apply里混入响应式断点(如md:p-8)或自定义属性(如transform: scale(0.95)),否则脱离 Tailwind 工具链,调试和主题切换都会出问题 - 修饰符类(如
card--featured)应只表达视觉变体,不用于状态控制(别写card--loading);状态逻辑交给 JS 控制 class 切换更可靠
HTML 模板里怎么写才不破坏分层
BEM 类名和 Tailwind 类名必须职责分明:BEM 负责结构定位与测试选择器,Tailwind 负责视觉表现。混在一起写(比如 card__header--compact)会彻底破坏 BEM 的语义价值。
- ✅ 正确:
<div class="card card--featured"><div class="card__header p-4 bg-white">——card__header供 JS 查询和 E2E 测试定位,p-4等负责渲染 - ❌ 错误:
<div class="card__header--compact p-2">——--compact是 BEM Modifier,不该和p-2合并在一个 class 里 - ❌ 更危险:
<div class="card__header md:flex">—— 把响应式逻辑塞进 BEM 类名,导致服务端渲染时无法判断断点,也破坏了类名的可读性 - 关键判断点:如果删掉所有 BEM 类,仅靠 Tailwind 类还能维持页面基本结构和功能,说明分层是健康的;反之,如果删掉 BEM 类后 JS 逻辑崩、测试失败、Storybook 快照错乱,那说明 BEM 已退化成装饰前缀,需要重构
真正难的不是写对正则或记住 @layer 语法,而是每次加新 BEM 类时,要同步确认它是否承载了不可替代的语义——比如是否被自动化测试引用、是否出现在 Figma 标注里、是否用于跨框架 Web Component 的 class 接口。这些地方一旦松动,BEM 就只剩下一堆长得像的字符串了。


















