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 容器(如 ),不能凭空造
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 叫这个名字”。
- 双下划线










