bem要求块独立、类名平铺、禁止嵌套选择器;按钮等块必须仅依赖自身类名,布局调整由父块修饰符控制,元素不可跨层嵌套,scss中仅允许&__element、&--modifier、&:hover三种安全写法。

块与块之间可以嵌套,但类名不能互相绑定
HTML 里一个 card 里面放一个 button,完全合法;但 CSS 里绝不能写 .card .button。BEM 的块是独立语义单元,button 的样式必须只依赖自身类名,不感知父容器。
常见错误现象:团队成员在 button.scss 里偷偷加了 .card .button { padding: 8px; },结果按钮挪到 modal 里就变小了——这不是 bug,是语义失控。
- 每个块的样式文件只包含以该块名为根的选择器:
.button、.button__icon、.button--primary - 布局微调(比如 card 里的 button 要更紧凑)应由父块通过修饰符或子元素控制:
.card--compact .button,而非污染 button 自身 - 若某按钮永远只出现在 card 中且无独立逻辑,它就不该是块,而是
card__action元素
元素不能跨层嵌套,三层类名如 card__header__title 是硬性违规
浏览器不会报错,但这类命名等于主动放弃组件可维护性。它把样式锚定在 DOM 路径上,而不是语义角色上。
真实场景中,card__header__title 往往意味着你本该拆出一个 heading 块,或者用 heading--in-card 修饰符收敛视觉变体。
- 判断标准就一条:这个 UI 片段会不会在别处复用?会 → 提为独立块;几乎不会 → 用修饰符或
data-context -
card__header是元素,不是块,它不能拥有自己的子元素;它的内容要么是card__title(提升为同级),要么是heading(新块) - SCSS 里禁止写
&__header { &__title { ... } },编译后生成非法类名,且误导后续维护者以为header是可扩展的块
嵌套 DOM 结构 ≠ 嵌套类名,BEM 要求类名“平铺”而非“滑动”
BEM 不要求 HTML 扁平化。你可以有 <div class="card"><div class="card__body"><div class="card__content">
<h3 class="heading"> 这样的五层 DOM,只要类名归属清晰就行。
</h3>
<p>关键在类名是否表达“我是谁”,而不是“我在哪”。<code>heading 就是 heading,不是 “card body 里的 content 下的 h3”。
- 允许的嵌套:
<div class="comment"><div class="comment--nested"><div class="comment__content"> —— 每个 <code>comment都是独立块,--nested只调整缩进/字号等表现 - 禁止的嵌套:
comment__reply__content—— 它假装存在一个叫reply的中间块,但这个“块”既不能单独使用,也没有自己文件和测试 - 如果某个子结构纯属布局辅助(比如
flex-container),直接去掉类名,用card__header--flex修饰符控制即可 - 唯一允许的写法只有三个:
&__element、&--modifier、&:hover(且需 JS 切换类名,不靠伪类驱动状态) - 禁用所有含空格的写法:
& .child、& > *、&__item a—— 它们产出后代选择器,破坏 BEM 原子性 - 修饰符必须作用于块本身:
.card--large .card__header才能支持组合(如.card--large.card--featured),而.card__header--large无法叠加
Sass 中用 & 时,只认三种安全模式
& 是字符串拼接器,不是语义校验器。它不管你是写对还是写错,只管把父选择器原样塞进去。
一旦写成 .card { &__header { &--large { ... } } },编译出来就是 .card__header--large —— 这个类名暗示“header 自己变大”,但业务需求其实是“整个 card 处于 large 状态时,header 要响应式调整”。语义已偏移。
__ 或 -- 之前,停下来问一句:这个东西,脱离当前 DOM 还能活吗?











