bem 不允许 card__header__title 这类三层命名,因违反 block__element 规则;正确做法是 card__title 或独立 heading block,scss 中 &__ 仅限三类安全用法,否则易生成非法类名。

card__header__title 这类名字根本不能用
它不是风格问题,是直接违反 BEM 核心规则:Block__Element__Element 三层结构不合法。浏览器不会报错,但会导致 card__header__title 无法单独复用、无法脱离 DOM 路径存在、SCSS 嵌套时容易误生成非法类名,而且一旦 card__header 类名变更(比如改成 card__section),样式就静默失效。
孙子级 DOM 结构 ≠ 孙子级类名
BEM 的 __ 表示“属于 Block”,不是“在 HTML 里嵌套了几层”。哪怕真实 DOM 是 <div class="card"><div><div>
<h2 class="heading">,只要这个 <code>h2 是 card 的标题,就该叫 card__title;如果它语义上是通用标题,就该抽成独立 Block,比如 heading 或 section-title。
- 需要复用?→ 单独定义
headingBlock,加 Modifier:heading--in-card-header - 只在卡片 header 出现且样式强依赖?→ 父级微调布局:
.card__header .heading { margin-bottom: 8px; },但仅限间距、对齐等一层作用,不写color、font-size等核心样式 - 一次性上下文(如折叠面板里的二级标题)?→ 用 State 类:
class="heading is-subheading",或 data 属性:data-context="accordion"
SCSS 里哪些 & 写法会偷偷造出非法类名
& 不是万能前缀拼接器,它只安全用于三类场景:&__element、&--modifier、&:hover(且需 JS 配合切换)。其他都危险:
-
.card { &__header { &__title { } } }→ 编译出.card__header__title,直接违规 -
.card { .header { &__title { } } }→ 编译出.header__title,语义断裂 -
.card { &:hover { &__icon { } } }→ 编译出.card:hover .card__icon,含空格,违背扁平性 - 媒体查询必须
@at-root提级:.card { @at-root @media (max-width: 768px) { &__title { } } },否则规则无效
真要响应父级状态,子元素类名必须显式声明
别写 .card--expanded .card__title 这种后代选择器——它让 card__title 失去独立可用性。正确做法是:JS 同时添加 card--expanded 和 card__title--expanded,CSS 定义 .card__title--expanded 的完整样式。
- ✅ 合规:
.card__title--expanded、.field-email__input--invalid - ❌ 违规:
.card-title--expanded(丢失 block 归属)、.input--invalid(脱离上下文) - 工具链(如
postcss-bem、VS Code 插件)全靠这种完整路径识别层级,简写等于自废诊断能力
__ 之前,得停下来问一句:这个东西,是不是真的只活在这个 Block 里?还是它早该有自己的名字和边界?











