card__header__title是非法类名,因bem严禁element嵌套element,它错误将card__header当作block,违反“元素必须直属于block”核心规则,导致样式失效、复用困难、调试不便。

card__header__title 为什么是非法类名
它不是语法错误,但直接违反 BEM 的核心契约:Element 必须直属于 Block,不能嵌套在另一个 Element 下。card__header__title 暗示 header 是一个 Block,但它只是 card 的一个 Element —— 这会让样式、复用、调试全部失效。
常见错误现象:
- DevTools 里搜
title找不到对应样式,因为类名是拼凑的,不是语义化的 - 给
card__header外层加个 wrapper:<div class="wrapper"><div class="card__header">...</div></div>,card__header__title就完全不生效 - 想把标题抽到用户页复用?不行,它被 DOM 路径锁死了
遇到 DOM 有三层嵌套,HTML 和类名怎么写才合规
BEM 不要求 HTML 扁平化,但要求类名归属清晰。DOM 可以是 <div class="card"><div class="card__header">
<h2 class="heading">,关键在于 <code>heading 是独立 Block,不是 card 的子孙元素。
判断标准就一条:这个 UI 片段会不会在别处复用?
- 会复用 → 提为独立 Block:
heading、dropdown、list - 几乎不复用,但强依赖容器 → 用 Modifier:
heading--in-card-header - 一次性弱复用(如折叠面板里的二级标题)→ 用 State 类:
class="heading is-subheading" - 样式高度依赖容器又不想污染命名 → 用
data-context:<div data-context="modal"><button class="button"> <h3>SCSS 里写 &__header &__header__title 会出什么问题</h3> <p>这种嵌套写法编译后生成 <code>card__header__title,直接产出非法类名,而且掩盖了设计缺陷。实际影响:
- 开发者误以为
&__header是可复用的“子块”,给它加 padding/margin,破坏card__header作为纯 Element 的语义 - 一旦把
header__title拆成独立 Block,所有 SCSS 嵌套逻辑得重写,维护成本翻倍 - 团队协作时,新人看到
card__header__title会默认这是“合理结构”,没人敢动,债务越积越深
多层嵌套类名对性能和可维护性的真实影响
浏览器 CSS 匹配是从右往左执行的。
card__header__title看似只是一个类名,但它的存在往往伴随深层后代选择器(比如.card .card__header .card__header__title),导致引擎反复回溯父级节点。更实际的问题是维护成本:
- 改一个中间类名(比如把
card__header改成card__top),所有依赖它的三层类名全失效 - 长类名如
page-layout__main-content__article__header__title在编辑器里难以阅读,也难被 Grep 或 IDE 全局搜索准确定位 - 工具链(如
postcss-bem-linter)能静态报错,但无法修复已存在的隐性耦合
真正难处理的不是命名规则本身,而是当多个团队共用同一套组件库时,有人偷偷把
card__header__title当作“快捷写法”塞进 PR —— 它不会让 CI 失败,但会在三个月后让重构变成一场灾难。 - 开发者误以为











