BEM是命名冲突时最省心的兜底方案,通过Block__Element--Modifier结构锚定语义、约束层级、配合Stylelint和CSS Modules工具链实现自动化校验与隔离。

命名冲突时,BEM 是最省心的兜底方案
当你在多个组件里反复纠结 btn-primary 还是 primary-btn,本质不是审美问题,而是缺乏约束。BEM(Block__Element--Modifier)不强制你“多写”,而是用结构锚定语义:search-form__input 明确属于 search-form 块,search-form--compact 是它的变体——不需要记忆“哪个前缀优先”,靠命名本身防冲突。
实操建议:
- 所有块名必须对应一个真实 DOM 容器(如
<div class="card">),不能凭空造card-header却没card - 双下划线
__只用于直接子元素,嵌套三层以上就该拆新 Block(比如card__body__list__item是错的,应为card__body+list两个 Block) - 用 PostCSS 插件
postcss-bem自动校验命名层级,避免手滑写成card__header__title
团队协作中,stylelint 配置比文档更管用
光写《CSS 命名规范》文档没人看,但把规则塞进 .stylelintrc.js 后,VS Code 保存即报错:Expected class selector to be kebab-case。这才是真正落地的约束。
关键配置项(需搭配 stylelint-selector-bem-pattern 插件):
立即学习“前端免费学习笔记(深入)”;
module.exports = {
rules: {
"selector-class-pattern": [
"^([a-z][a-z0-9]*)(__[a-z][a-z0-9]*)?(--[a-z][a-z0-9]*)?$",
{ message: "Class name must follow BEM: block__element--modifier" }
]
}
};
注意点:
- 正则里
[a-z0-9]禁止数字开头(1col-layout会报错),避免 CSS 选择器解析歧义 - 如果项目已存在大量
camelCase类名,先用disable-line注释临时绕过,再批量替换,别硬扛 - CI 流程中加
npx stylelint "**/*.css",防止带错误命名的代码合入主干
工具链里最常被忽略的环节:CSS Modules 的局部作用域没解决命名焦虑
很多人以为开了 css-modules 就不用纠结命名了,结果写出 styles.button 和 styles.button2 ——这比全局命名还糟。CSS Modules 的价值在于隔离,不是放养。
正确用法:
- 文件名即 Block 名:
Button.module.css里只写.root、.icon、.disabled,编译后自动变成Button_root_abc123 - 跨组件复用样式?用
:global(.btn-reset)导入原子类,而不是在每个 Module 里重复定义.small、.large - 配合
webpack的localIdentName配置,把哈希长度缩到 4 位([name]_[local]_[hash:base64:4]),避免生成过长类名影响调试
当设计系统升级时,重命名脚本比人工搜索更可靠
设计稿从「主按钮」变成「CTA 按钮」,你不可能靠眼睛扫完所有 btn-primary。用 jscodeshift 写个 codemod 脚本,10 分钟批量改掉所有引用:
module.exports = function transformer(fileInfo, api) {
const j = api.jscodeshift;
const root = j(fileInfo.source);
// 替换 HTML 中的 class
root.find(j.Attribute, { name: { name: 'class' } })
.forEach(path => {
const value = path.value.value?.value;
if (value && value.includes('btn-primary')) {
path.value.value.value = value.replace(/btn-primary/g, 'cta-button');
}
});
return root.toSource();
};
执行命令:npx jscodeshift -t ./rename-btn.js src/**/*.{js,tsx}
提醒一句:
- 运行前先
git stash,脚本可能误改字符串字面量(比如日志里的"btn-primary clicked") - HTML 模板文件(
.html或.vue)需额外用html-codemod处理,JSX 语法树和 HTML 树不兼容 - 改完立刻跑视觉回归测试(如
percy),确认cta-button样式没因覆盖丢失
命名从来不是选美比赛,而是降低后续修改成本的基础设施。越早用工具固化规则,越晚要花时间解释“为什么这个 class 叫这个名字”。










