初学者常把双下划线“__”当成“所有嵌套层级的分隔符”,实则它是BEM命名法中表示修饰符或子元素的约定符号,如card__header表示card的子元素,card__header_title表示card__header的子元素,并非通用DOM层级分隔符。

初学者常把__当成“所有嵌套层级的分隔符”
看到 DOM 里 <div class="card"><div class="card__header"><h2 class="card__header__title"></h2></div></div>,就以为双下划线该一路往下串——这是最典型的误用。BEM 的 __ 不是“嵌套标记”,而是“直属归属声明”:它只表示“这个元素直接属于某个 Block”,不反映 HTML 深度。
-
card__header__title是非法命名,浏览器不会报错,但语义断裂:title 并不直接属于 card 块?还是属于 header 元素?工具无法解析,团队成员也无法快速判断职责边界 - 正确做法是回归块上下文:
card__title(哪怕它在 DOM 中确实嵌在card__header里) - 如果
title在多个块中复用(比如也出现在user-profile),那它本身就该是独立 Block:title,而不是依附于谁的 Element
混淆__和--导致修饰符加错位置
写成 card__header--expanded 看似合理,但实际暴露了对 Modifier 作用域的误解:修饰符不是“让某个元素看起来展开”,而是“表达这个 UI 单元当前处于展开状态”。一旦状态逻辑从 Block 层下沉到 Element 层,后续维护就会失控。
-
card--expanded表示整个卡片处于展开态,其内部所有子元素样式由该状态统一驱动 -
card__header--expanded暗示 header 可以独立展开,而 card 本身未展开——这在多数设计系统中并不存在对应语义 - 更危险的是混用:
card--expanded card__header--collapsed,CSS 选择器无冲突,但业务逻辑已自相矛盾
用单下划线或中划线替代__破坏工具链与协作基础
BEM 解析器、clsx 插件、Sass 的 &__ 语法、甚至 IDE 的类名跳转,全都依赖 __ 和 -- 作为唯一结构锚点。换成 _ 或 -,等于主动关闭所有自动化支持。
-
card_header会被误判为 block 名是card、element 是header;但若真实 block 名是user-card,user-card_header就完全无法拆解 - PostCSS
@bem插件会静默跳过非标准命名,不报错也不修复,问题拖到运行时才暴露 - 新人看到
form_input--disabled,会自然认为input是 element,却不知道它本应是form__input——这种认知偏差会在两周内传染给整个前端组
把__当“CSS 选择器路径”来写,反而加剧 DOM 耦合
有人写 .card__content p 或 .card__header h2,以为这样更“精准”。其实这恰恰违背 BEM 初衷:BEM 的目标是让样式脱离 HTML 标签和嵌套关系,而这类选择器又把样式绑死在特定标签和层级上。
立即学习“前端免费学习笔记(深入)”;
- 一旦设计师把
<h2 class="card__title"></h2>改成<div class="card__title">,样式立刻失效 <li>正确的 CSS 写法只有 <code>.card__title { },不带空格、不带标签、不带父级 - 如果真需要区分标题级别,应该用不同 Element 名:
card__heading-1、card__heading-2,而非依赖 HTML 标签
真正难的不是记住双下划线怎么写,而是每次敲下
__ 之前,得想清楚:这个类名是否表达了“它属于谁”和“它是什么”,而不是“它在 HTML 里第几层”。


















