bem能直接废除嵌套选择器,因其用单类名(如nav__item)替代深层后代选择器(如.header .nav .item),实现一次哈希查找、零回溯;同时严格禁止element嵌套(如card__header__title非法),要求每个独立ui单元自成block,确保语义清晰、复用自由。

为什么 BEM 能直接废掉 .header .nav .item 这类写法
浏览器匹配 .header .nav .item 时,从右往左找所有 .item,再逐个向上验证是否在 .nav 内、再是否在 .header 内。DOM 越深、节点越多,回溯开销越大;而 nav__item 是单类名,浏览器一次哈希查找就命中,不查父级、不回溯。
- 实测:5 层嵌套选择器在低端 Android 设备上 Recalculate Style 耗时比单类名高 4 倍以上
- 维护成本归零:改
.nav类名?nav__item完全不受影响 - 复用无门槛:把
nav__item拿到弹窗里用,样式照常生效,不用重写选择器
card__header__title 是非法类名,不是手误而是语义崩坏
card__header__title 看似顺理成章,实则违反 BEM 最核心约束:Element 必须直接隶属于 Block,不能嵌套 Element。它等于在声明 “header 是 Block”,但 card__header 本身只是 card 的一个 Element,没有资格充当 Block 角色。
- 后果严重:改
card__header结构(比如换成card__section),card__header__title就静默失效 - 无法抽离:这个类名绑死了 DOM 路径,拿不到其他页面复用
- SCSS 里写
&__header { &__title { } }会编译出非法类名,且容易误给card__header加 padding,破坏 Element 的纯展示语义
HTML 可以嵌套,但类名必须按语义分块,不是按 DOM 层级拼接
DOM 嵌套 4 层完全没问题,关键是谁挂什么类名。错误做法是让所有子元素都挂在顶层 Block 下;正确做法是识别出独立 UI 单元,赋予它自己的 Block 名。
- 反模式:
<div class="dashboard"><div class="dashboard__content"><div class="dashboard__content__table">...</div></div></div> - 正解:把
table抽成独立 Block,写<div class="table"><div class="table__row"><div class="table__cell">...</div></div></div> - CSS 仍可控制上下文:
.dashboard .table控制布局位置,但命名不耦合,table自身的table__row和table__cell可复用到任何页面
__ 和 --,而是每次加一层 DOM 时,停下来问一句:这个节点是不是一个能独立存在、有明确功能边界的 UI 单元?如果不是,它就不该有自己的 BEM 类名——更不该靠多一个 __ 来“假装”合理。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











