BEM通过命名约定显式声明作用域,避免深层后代选择器因DOM结构调整而失效、语义模糊、性能下降及协作混乱等问题。
为什么
这类选择器越来越难维护
深层后代选择器本质是把 DOM 结构耦合进了 CSS,一旦 HTML 层级微调(比如加个
包裹、抽离组件),样式就悄无声息地失效;更麻烦的是,它无法体现语义归属——你根本看不出这个
到底属于导航、还是用户菜单、还是页脚。
浏览器匹配时需逐层向上回溯,层级越深性能损耗越明显(尤其在动态插入节点后重排)
多人协作中,不同开发者对“该不该加一层 wrapper”没有共识,导致同类模块的 DOM 深度不一致
使用 CSS-in-JS 或 Shadow DOM 时,这类选择器直接失效或需要额外穿透配置
用 BEM 命名直接替代后代关系表达
BEM 不是强制规范,而是用命名约定显式声明作用域:一个块(Block)内部的元素(Element)和修饰符(Modifier)靠名字本身关联,不再依赖 HTML 层级。
是块,
和
是它的元素,中间双下划线
就是“属于”的语法糖
即使
在 DOM 中被嵌套进 5 层
,只要 class 名不变,样式就稳住
避免用
这种模糊写法——
可能来自其他块,冲突风险高
示例对比:
BEM 实际落地时最常踩的三个坑
不是起对名字就完事,关键在约束力和一致性。
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
立即学习
“
前端免费学习笔记(深入)
”;
别把 Block 名起成泛义词:
、
、
—— 它们缺乏上下文,容易跨模块复用错,应改为
、
Element 不能嵌套 Element:
是反模式,正确是
+
(同一 Block 下平级)
Modifier 必须依附于 Block 或 Element:
可以,但单独写
就失去语义,也难定位来源
已有项目怎么渐进式迁移到 BEM
全量重命名不现实,优先从高频修改、多人共用、易出问题的模块切入。
先扫描 CSS 文件中出现 3 次以上的深层选择器,比如
,把它对应模块定为迁移目标
新写的组件/样式,一律用 BEM 命名;旧代码不动,但禁止新增同类后代选择器
用 ESLint 插件
检查新提交的 CSS,拦截非 BEM 写法
注意:BEM 不解决样式隔离,若需更强封装,得配合
(Vue)或
(Shadow DOM)
BEM 的核心不是让 class 名变长,而是让每个 class 的职责和归属一目了然。真正难的不是命名规则,是团队在每次加 wrapper、抽子组件、改结构时,都愿意多想半秒:“这个 class 该属于谁?”
.header .nav .item .linkdiv.link.nav.nav__item.nav__link__.nav__linkdiv.nav .link.link/* ❌ 后代模式,脆弱 */
.header .nav .item .link { color: blue; }
/ ✅ BEM 模式,明确且解耦 /
.header { }
.nav { }
.navitem { }
.navlink { color: blue; } / 不依赖父级是否存在,也不关心它在 DOM 里嵌多深 /
.list.box.container.product-list.sidebar-box.nav__item__icon.nav__item.nav__item-icon.nav--vertical.vertical.modal .content .form .inputstylelint-selector-bem-patternscoped:host