BEM规范通过“块__元素--修饰符”结构实现语义自解释:user-card__avatar--large直接表明归属、角色与状态,无需查HTML或文档。

新成员打开一个组件的 CSS 文件,30 秒内就能判断出它负责什么、能怎么用、有哪些状态变体——BEM 不是教人写 CSS,而是让人不用猜。
为什么看到 user-card__avatar--large 就比看到 .avatar 更快理解?
人脑对无上下文字符串的处理成本很高。.avatar 出现在审查元素里,得翻 HTML 才知道它属于哪个模块;而 user-card__avatar--large 自带三重语义:归属(user-card)、角色(avatar)、状态(large)。不需要查文档、不依赖记忆、不靠团队口头约定。
常见错误现象:card-title 和 product-card__title 并存,新人改了前者却发现购物车页没生效——因为实际生效的是后者,但没人告诉过他“title”到底属于哪个块。
- 块名(
user-card)必须是业务词,不是视觉词(禁用big-box、left-panel) - 元素名(
avatar)不能脱离块独立存在,__avatar合法,.avatar或__image都不行 - 修饰符(
--large)只表达可预期的状态,不是随意加的尺寸描述(--lg容易失控,--large可收敛)
如何让新成员 30 分钟内看懂一个组件的样式结构?
关键不是讲规则,而是把规则“焊死”在文件里。每个 BEM 块对应一个独立 CSS 文件,开头加标准化注释。
立即学习“前端免费学习笔记(深入)”;
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
示例注释:
/* * @block user-card * @description 用户资料卡片,支持头像尺寸/信息折叠/操作按钮显隐 * @modifiers: --compact, --with-actions, --loading */
新成员打开 user-card.css 就立刻知道:这个组件叫什么、哪些类名可以直接复用、哪些状态是设计认可的——不需要问人、不靠试错、不翻 Git 历史。
- 禁止跨文件定义同一块的样式(比如
form.css里写user-card__footer) - 子组件仍需独立块名(
dropdown里的菜单不是dropdown__menu,而是menu,除非它绝不出现在 dropdown 外) - 老项目迁移时,优先给新组件、高频修改区、冲突严重区打上 BEM 标签,而不是全量重命名
工具链怎么防止新人手滑写错 BEM?
靠 Code Review 拦不住拼写错误,必须让违规在保存时就报错。
实操建议:
- 用
stylelint-selector-bem-pattern插件,配置{ "componentName": "[a-z][a-zA-Z0-9]+", "styleType": "bem" },自动拦截.header .logo或btn-primary - VS Code 安装 “BEM Helper”,输入
user-card回车自动补全user-card__和user-card-- - CI 流程中跑
npx stylelint "**/*.{css,scss}",失败即阻断合并
容易被忽略的一点:BEM 的价值不在“防冲突”,而在“降低推理成本”。哪怕项目用了 CSS Modules,styles.avatar 依然无法告诉你这个 avatar 属于哪个业务模块——而 user-card__avatar 可以。命名一旦脱离语义锚点,再强的工具也救不回协作效率。

















