BEM中双下划线__仅用于块与直属元素连接,如menu__item;深层元素应回归块上下文(menu__icon),非嵌套延伸;修饰符用--分隔,如button--large;避免拼接错误,推荐使用bem-cn等工具。

怎么用双下划线写BEM元素名才不混乱
双下划线 __ 在BEM里只用于连接块(Block)和它的直接子元素(Element),不是随便加的分隔符。很多人一上来就给所有嵌套层级都加 __,结果写出 header__nav__item__link 这种东西——这已经违背BEM本意了。
-
__只能出现在块名之后、且仅一层:正确是menu__item,错误是menu__item__icon - 深层子元素要回归到块上下文:想样式化菜单里的图标,应该写
menu__icon,而不是从item继续延伸 - 如果真需要表达“某元素下的某元素”,优先考虑是否该拆成新块:比如
user-card__avatar比user-card__content__avatar更合理
CSS选择器里为什么不能只靠类名拼接来模拟嵌套
BEM不鼓励写 .header .nav .item 这类依赖DOM结构的选择器,因为一旦HTML微调(比如把 nav 提到 header 外),样式就断了。双下划线命名本质是把结构关系“固化”进类名,让样式与结构解耦。
- 用
.header__nav就明确表示“这是 header 块的一部分”,哪怕它被挪到页面任意位置,样式依然生效 - 浏览器匹配
.header__nav比匹配.header .nav略快(单类名 vs 后代选择器),尤其在复杂DOM中差异更明显 - 工具链如 PostCSS 或 Sass 的嵌套语法(
&__item)只是写法糖,最终输出仍是扁平类名,别误以为它会生成后代选择器
遇到复合元素时,双下划线和短横线怎么选
当一个元素本身有状态或变体(比如按钮有大小、颜色、加载态),BEM规定用单短横线 - 连接修饰符(Modifier),而双下划线 __ 仍严格保留给块-元素关系。
- 正确:
button__text(元素)、button--large(修饰符)、button--loading(修饰符) - 错误:
button__text--large—— 元素本身不该带修饰符,应由块统一控制;真要差异化,写button--large__text也不对,应保持button--large覆盖内部所有子元素 - 例外:极少数场景需限定修饰符作用范围(如仅影响某个子元素),可用
button__text--highlighted,但必须文档化说明,避免团队误用
Vue/React组件里用BEM双下划线要注意什么
框架组件常动态生成类名,容易把 BEM 写成字符串拼接(如 `${block}__${element}`),看似灵活,实则埋雷:拼错、漏空格、大小写不一致都会导致样式失效。
立即学习“前端免费学习笔记(深入)”;
- 别手写拼接,用现成工具:Vue 推荐
vue-bem-cn,React 推荐bem-cn或@bem-react/classname - 组件 props 传入的
element名必须校验合法性:禁止含空格、特殊符号、开头数字(button__2nd-item是非法的,应为button__second-item) - 服务端渲染(SSR)时注意类名一致性:客户端生成的
modal__overlay和服务端输出的modal__backdrop不匹配,会导致 FOUC 或样式丢失
双下划线看着简单,但真正卡住人的往往不是语法,而是“这个东西到底算不算当前块的直属元素”——每次加 __ 前,先问一句:它语义上是否不可分割地属于那个块?如果不是,大概率该独立成块,或者用修饰符收口。










