bem 本质是将样式冲突转化为可定位的结构错误,而非避免冲突;其类名不唯一,依赖构建层校验、白名单约束与作用域声明来保障可靠性。

直接写 .button 或 .header 必然冲突,BEM 不是“避免冲突”的技巧,而是把冲突变成可定位、可审查的结构错误。
为什么 BEM 类名还会撞车?
BEM 本身不生成唯一类名,它只是命名约定。两个模块都写了 .search-form__input,最终打进同一份 CSS 文件里,后定义的规则就会覆盖前一个——浏览器不认“谁写的”,只看层叠顺序和选择器权重。
- 常见现象:
.user-card__avatar在用户页是 40px,在后台页被另一个同名类设成 24px,结果全站头像变小 - 团队不敢删旧类,因为没人敢确认哪个页面还依赖它
- JS 仍能用
document.querySelector('.form__input')拿到并改样式,暴露面大
真正起作用的是构建层 + 命名白名单
光靠人写对 BEM 名没用,必须让工具守住边界。
- 用
stylelint-selector-bem-pattern校验:禁止出现.btn、.input这类裸名,只允许block__element--modifier结构 - 配合
postcss-bem-linter配置componentName白名单,比如限定 block 只能是['button', 'card', 'search-form'],防止有人随手写.my-button - 所有新组件 CSS 文件开头加注释声明作用域:
/* @scope product-list */,CI 中可扫描该标记做归属校验 - 禁用全局 CSS 文件(如
base.css)中出现__或--,这类文件只放html、body、h1等基础重置
多人协作时 JS 拼 className 的致命坑
手拼字符串看着快,实际在 CI 环境下极易因大小写、空格、连字符漏写而挂掉。
- ❌ 危险写法:
className={`button button--${variant} ${hasIcon ? 'button__icon' : ''}`}(缺空格、无防错、button__icon脱离 block) - ✅ 推荐封装常量:
const BLOCK = 'search-form'; const cn = (e, m) => `${BLOCK}${e ? '__' + e : ''}${m ? '--' + m : ''}`,调用cn('input', 'disabled')得到search-form__input--disabled - 若用 CSS Modules,坚持
import styles from './Button.module.css'+className={styles['button--loading']},永远不硬写哈希类名
最容易被忽略的不是怎么写 BEM,而是每次写 class 前是否真问过:“这个样式属于谁?它会不会在别的上下文里意外生效?”——这句话比任何工具配置都管用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











