BEM通过扁平化类名(如.card__title)确保所有选择器权重均为0,1,0,从源头避免权重差异,而非事后拉平;它本质是命名契约,统一抽象层级,解决团队协作中的样式失控问题。

为什么.btn-primary有时赢不了#header .nav li a
CSS优先级不是“谁写在后面谁赢”,而是按选择器的“权重”算出来的。类名.btn-primary权重是 0,1,0;而#header .nav li a含1个ID、1个类、2个标签,权重是 1,1,2 —— 直接碾压。BEM本身不改权重,但能帮你避开高权重陷阱。
- ID选择器(
#header)权重太高,一个就顶100个类,日常开发中尽量不用 - 后代选择器(
.nav li a)里每多一层标签,就多加0,0,1,三层层叠很容易无意堆出高权重 - BEM强制你用
.menu__item--active这种扁平命名,天然回避.menu li.active a这类嵌套写法
怎么让.card-title和.card-body权重真正一致
关键不是“拉平”,而是“从一开始就不制造差异”。BEM要求所有样式都挂载在块级类上,不依赖上下文,这样每个类的权重自然都是 0,1,0。
- ❌ 错误写法:
.card h3(权重0,0,1) vs.card .card-body(权重0,1,1)→ 已不一致 - ✅ 正确写法:
.card__title和.card__body→ 都是单类,权重严格相等 - 如果真要区分状态,用修饰符:
.card__title--large,不是.card--large .card__title
遇到第三方库样式(比如antd)强行用!important怎么办
BEM不能帮你删掉别人的!important,但能让你的覆盖更可控、更少副作用。
- 别用更高权重硬刚(比如加ID或一堆嵌套),那只会让后续维护雪上加霜
- 用BEM约定好的命名,在自己组件内写
.my-table__cell--highlight,然后靠源码顺序后置加载,靠0,1,0对0,1,0赢 - 如果对方用了
!important,你只能也用!important——但BEM结构让你清楚知道“只在这里加”,不会污染全局
:is()和:where()能替代BEM吗
不能。它们解决的是“写法冗余”,不是“权重失控”。
-
:is(.btn, .btn-primary, .btn-secondary)权重取组内最高(即0,1,0),看起来“扁平”,但没约束结构,团队照样可能写出:is(#main .sidebar ul li a) -
:where()权重恒为0,看似完美,但它会削弱选择器有效性——浏览器会忽略语法错误部分,调试时更难定位问题 - BEM的价值不在语法糖,而在命名即契约:看到
modal__footer-button,你就知道它不该依赖.modal.is-open的状态
真正的难点从来不是算权重,而是让所有人写的CSS在同一个抽象层级上对话。BEM是协议,不是语法糖。漏掉这点,再新的伪类也救不了样式混乱。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











