真正卡住bem落地的是块边界模糊、element过度拆分、modifier语义失控三件事:block须独立存在且有明确复用场景,element名禁用父级回溯(如.card__title非.card__card-title),modifier须原子化且不嵌套(如button--primary button--disabled而非button--primary--loading)。

直接用 BEM 命名写一堆 .card__title、.modal__footer--sticky 并不等于建成了设计系统——它只是命名起步,真正卡住落地的是块边界模糊、Element 过度拆分、Modifier 语义失控这三件事。
如何定义一个“可沉淀”的 Block 而不是临时容器
Block 必须满足两个硬条件:能独立存在、有明确复用场景。比如 .user-card 合规,而 .section-2 或 .page-header 不合规——它们只是视觉分组,没业务语义,换页就失效。
- 判断方式很直接:这个类名删掉后,对应 DOM 是否还能被其他页面/模块安全复用?不能 → 它不是 Block
- 常见错误是把布局容器当 Block,比如给 flex 包裹层起名
.grid-row,结果后续所有网格都得复制它;正确做法是让.card、.list-item这类真实组件自己处理内部布局 - 目录结构必须对齐:每个 Block 对应一个独立目录(如
/components/card/),里面只放card.css、card.js,禁止出现card-button.css这种子块文件——那是 Element,不该有独立生命周期
Element 命名为什么不能回溯父级语义
.card__card-title 是典型冗余,BEM 要求 Element 名称只用名词、不带父级前缀,因为 __title 已隐含归属关系。强行加 card- 会模糊职责边界,且一旦抽成独立 Block(如 .text-heading),原命名就失去意义。
- Element 必须是 Block 的必要组成部分,且不可脱离 Block 单独使用:
.card__image合规,.card__image-wrapper-inner违规——三层嵌套暴露了结构假设,实际只需.card__image+ Modifier 控制尺寸或圆角 - 禁止用动词命名 Element:
.card__show-more错误,这是状态,该由.card--expandable+ JS 控制类名切换 - SCSS 中必须用
&__title,禁用.card__title这种后代选择器写法,否则等于放弃 BEM 的作用域隔离能力
Modifier 怎么避免变成命名黑洞
Modifier 不是万能补丁,它是原子化、可枚举的状态开关。.button--size-14px 违规,.button--large 合规;.button--mobile 违规,响应式该由媒体查询包裹,而非塞进 Modifier。
- Modifier 必须依附于 Block 或 Element:
.button--disabled正确,.button__text--disabled错误——禁用状态属于整个按钮,不是文字自身的属性 - 禁止嵌套 Modifier:
.button--primary--loading看似合理,但实际应组合使用:button button--primary button--loading,保持扁平 - 构建工具要拦截风险:Vite + PostCSS 默认启用
cssnano的mergeLonghand,会导致button--primary button--disabled被压缩成button--primary,必须在配置中禁用该优化项
为什么 BEM 设计系统最难的不是写法,而是“谁来决定”
一个 .input-field 该拆成 .input + .validation-message 还是塞进单个 Block,没有技术标准答案——它取决于团队对“复用粒度”的共识。这类决策一旦松动,三个月后就会出现 .card__header__title--dark 这种三层嵌套,再没人敢动它。
真正有效的约束来自工具链:用 stylelint-selector-bem-pattern 校验类名格式,用 ESLint 插件禁止 JSX 中硬编码 button__icon 字符串,目录结构强制 Block 独立存放——不是靠文档说服人,而是让错误在保存时就报红。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











