header__logo--dark一眼就懂,因其结构强制表达三层信息:header是独立Block模块,__logo是其语义化Element,--dark是可预期的状态Modifier,无需查看HTML或JS即可明确作用域与边界。

因为类名本身已经携带了完整的上下文:谁(Block)、是什么(Element)、当前什么状态(Modifier),不需要跳转 HTML 或 JS 就能判断作用域和语义边界。
header__logo--dark 这种名字为什么一眼就懂?
它不是靠“约定俗成”,而是靠结构强制表达三层信息:
-
header是 Block —— 表明这是 header 模块的独立功能单元,不是泛义容器 -
__logo是 Element —— 表明它是 header 的一部分,且语义明确(不是__el-1或__img这种结构描述) -
--dark是 Modifier —— 表明这是可预期的状态变体,不是临时加的样式补丁
对比 logo-dark 或 dark-logo:前者无法判断归属模块,后者甚至可能被误认为是全局 logo 的暗色主题,而实际它只属于 header 块。
为什么不用看 HTML 就知道 .card__title--large 不会污染其他标题?
关键在单类名选择器 + 无空格结构:
立即学习“前端免费学习笔记(深入)”;
-
.card__title--large是一个完整类名,浏览器哈希查找一次命中 - 它不依赖 DOM 层级,哪怕
card__title在 HTML 里嵌套五层 div,只要语义是 card 的标题,就该叫这个 - 没有
.card .card__title这种带空格的选择器,也就不会因父级变动或意外插入节点而失效
DevTools → Computed Styles 里点开就能确认:有没有空格?有没有意外混入的 div 或 [data-]?有空格就是写错了。
Sass 里 & 嵌套最容易偷偷破坏 BEM 结构
& 是语法糖,不是 BEM 保障。常见翻车点:
-
.card { &__header { } }→ 编译为.card__header✅ -
.card { &.is-open { } }→ 编译为.card.is-open✅(合法修饰符) -
.card { &__header.is-open { } }→ 编译为.card__header.is-open❌(Modifier 应作用于 Block,不是 Element) -
.card { &__header &__footer { } }→ 看似合理,但实际生成两个独立类,没体现层级关系,也不利于复用
真正安全的写法是:修饰符永远绑定到 Block 类名上,比如 .card--expanded 控制整体展开态,而不是给每个子元素单独加状态类。
BEM 不解决层叠顺序问题。如果 .card__title--large 和 .card__title--small 同时存在且冲突,不是命名错了,而是 CSS 引入顺序或权重没管住——BEM 只管名字,不管谁覆盖谁。


















