BEM 的核心是通过 block__element--modifier 结构将归属、角色、状态三重语义硬编码进类名,实现人眼可读、机器可查、搜索可定位;它解决泛义类名冲突与结构选择器脆弱性问题,强制命名空间隔离与语义精确性。

直接说结论:BEM 不是让 CSS 更“好看”的命名风格,而是用 block__element--modifier 这种固定结构把归属、角色、状态三重语义硬编码进类名里——人眼可读、机器可查、搜索可定位,协作时不用问“这个类谁写的?管哪儿的?”,翻代码就能懂。
为什么 .btn 和 .header .logo 会在协作中引发冲突
泛义类名没有上下文,.btn 可能被登录页、弹窗、表单组件各自复用,但没人能保证它在所有地方都该有 margin-right: 8px;.header .logo 这种结构选择器更危险:DOM 微调(比如加个 wrapper)就导致样式失效,且审查元素只看到一堆零散类,根本分不清哪个规则来自哪层业务逻辑。
使用 BEM 后,每个组件自带命名空间:.auth-form__submit 只属于登录表单,不会影响 .settings-form__submit;.card__title 和 .modal__title 完全隔离,哪怕样式一模一样也不冲突。
-
.btn或.logo类名无法回答三个关键问题:属于哪个模块?是哪个组件的一部分?当前什么状态(如--disabled、--dark)? - BEM 强制用块名打头,
.header__logo和.article__logo天然隔离,哪怕共用同一份 HTML 标签结构 - 禁止
.header .logo这类嵌套选择器,避免因 DOM 结构微调导致样式失效
如何用 stylelint-selector-bem-pattern 卡死新增入口
靠文档和 Code Review 拦不住手滑。必须让违规类名在保存时就报错,否则新代码每天都在污染边界。
立即学习“前端免费学习笔记(深入)”;
安装插件:npm install --save-dev stylelint-selector-bem-pattern
在 .stylelintrc.js 中配置:
module.exports = {
plugins: ['stylelint-selector-bem-pattern'],
rules: {
'plugin/selector-bem-pattern': {
componentName: '[a-z][a-zA-Z0-9]+',
styleType: 'bem'
}
}
};
它会立刻拦截:.header .logo(结构选择器)、.btn-primary(非 BEM 格式)、CardTitle(大驼峰)、_input(下划线开头)
- CI 流程中加
npx stylelint "**/*.{css,scss}",失败即阻断合并 - VS Code 配合
BEM Tools插件,输入btn__text回车自动补全为btn__text,不支持btn_text或btn-text - 写错一个下划线(如
user_name)或破折号(如button-disabled),PostCSS 插件、Stylelint、VS Code 补全全部失效——不是“差不多就行”,而是正则匹配失败后直接跳过校验
React/Vue 中怎么避免 BEM 写崩或漏写
纯手写 className="user-card user-card__title user-card__title--large" 极易漏,重构块名时漏改一处,样式就断掉,且无报错。
正确做法是函数化生成,例如用 clsx + 自定义 BEM 工具函数:
const bem = (block) => {
return (element, modifier) => {
if (modifier) return `${block}__${element}--${modifier}`;
if (element) return `${block}__${element}`;
return block;
};
};
// 使用
const cn = bem('user-card');
<div className={cn('avatar', isCompact ? 'compact' : null)}></div>
- 禁止在 JS 里硬编码
el.classList.add('card__body')或拼接字符串:`${base}__${elem}--${mod}`—— IDE 无法跳转、搜索失效、重构漏改 - 修饰符必须作用于具体发生状态变化的 UI 单元,不是“整个组件”:
card__title--disabled✅,card--disabled .card__title❌(破坏样式隔离) - 块名必须和设计系统组件名完全一致:
user-profile-card不能缩写成profile-card,否则 Figma 插件导出类名与实际 CSS 对不上
BEM 的真正复杂点不在语法,而在于团队对“块”的共识——user-profile-card 是一个块,user-profile-card__avatar 是它的元素,但 user-profile-card__avatar--compact 是否该存在,取决于设计系统是否定义了 “compact” 是一种可复用的状态,而不是某个页面临时加的 width: 32px。这层语义判断,工具链帮不了你,得靠设计规范和 Code Review 共同守住。


















