card__header__title非法,因bem禁止block__element__element三层结构;它破坏语义隔离、复用性与工具链校验,正确做法是将title升为独立block(如heading)或用modifier(heading--in-card-header)及父级微调布局。

card__header__title 这类命名为什么不能用
它根本不是合法 BEM 类名。BEM 明确禁止 Block__Element__Element 三层结构,card__header__title 暗示 title 是 header 的子元素,但 card__header 本身只是 card 的一个 Element,不能作为父级承载另一个 Element。浏览器不会报错,但会导致:
• 类名无法独立复用(card__header__title 拆不出、测不了、改不了)
• SCSS 嵌套生成后语义断裂(&__header &__header__title 编译出非法名)
• 团队协作时没人敢动它——改一处,三处页面同时崩
DOM 有三层嵌套,HTML 和 class 怎么配才不破防
别让 HTML 结构牵着 CSS 走。真实 DOM 可以是 <div class="card"><div class="card__header">
<h2 class="heading">,关键在类名归属:<br>• 如果 <code>heading 在多个地方复用(用户页、弹窗、侧边栏),就定义为独立 Block:.heading {} .heading--in-card-header {}
• 如果它只在 card header 出现且样式强依赖上下文(比如字号/行高/颜色都得微调),用 Modifier + 父级布局控制:.card__header .heading { margin-bottom: 8px; }
• 禁止写 .card__header .heading 定义核心样式(如 color、font-size),只允许用于间距、对齐等一层微调
SCSS 里怎么写才不偷偷造出孙子名
SCSS 嵌套本身不危险,危险的是嵌套出后代选择器或非法类名:
• 别写 .card { &__header { &__title { ... } } } —— 编译后是 .card__header__title,直接违规
• 正确做法:每个 Block 单独文件,手写全名:.heading { ... }、.card__header { ... },靠 @use 或 import 组织依赖
• 若必须局部微调,用属性选择器:[data-in="card-header"] .heading { font-size: 1.1em; },比硬编码更可控
• 工具链加 stylelint-selector-bem-pattern,CI 阶段拦截 __.*__ 类名
真遇到“非孙子不可”的场景怎么办
极少数情况,比如折叠面板里的二级标题、弹窗 footer 中的按钮组,它们几乎从不在别处复用,且样式高度依赖容器:
• 优先用 State 类:<h3 class="heading is-subheading"></h3>,配合 .is-subheading { font-size: 0.9em; }
• 或用 data 属性标记上下文:<div data-context="modal-footer"><button class="button">,再写 <code>[data-context="modal-footer"] .button { margin-left: 8px; }
• 绝不写 modal__footer__button-group —— 它搜不到、切不出、抽离成本高,还让 button-group 失去语义独立性
最易被忽略的一点:BEM 不是“把 HTML 标签名转成类名”,而是判断这个东西“能不能脱离当前上下文存在”。能,就是新 Block;不能,就用 Modifier 或父级微调。这个判断一旦松动,后面所有复用、测试、维护都会卡住。











