bem类名变长是因为违背了其“每个block独立可复用”的初衷;三层下划线(如.header__nav__item__link)表明组件职责不清,应将可复用的子结构(如nav、list)提升为独立block,或用modifier(如button--in-card)表达上下文变体,避免深层嵌套。

多层级嵌套时BEM类名为什么会变长
当你写 .header__nav__item__link 这种结构,说明已经违背了BEM的初衷。BEM要求每个组件(Block)是独立、可复用的单元,__ 只用于描述该 Block 内的直接子元素,不支持“子元素的子元素”这种递进关系。一旦出现三层下划线,实际反映的是组件职责不清——比如 nav 本该是一个独立 Block,却被降级成了 header 的内部元素。
正确拆分嵌套:把子结构提升为独立 Block
遇到 .card__body__list__item__text 这类超长名,优先考虑是否该提取出新 Block。例如:
-
card是 Block,card__body是其 Element - 但
list很可能具备复用性(其他地方也要列表),应定义为独立 Block:list - 那么原结构应写成:
<div class="card"><div class="card__body"> <ul class="list"><li class="list__item"><span class="list__text"></span></li></ul> <p>这样既保持语义清晰,又避免命名膨胀。关键判断标准是:这个 UI 片段会不会在别处复用?是否拥有自己的逻辑或样式边界?</p> <h3>需要保留嵌套语义时,用 Modifier 而非深层 Element</h3> <p>有些场景确实需表达“某元素在特定上下文中的变体”,比如按钮在卡片内要缩小尺寸。这时不该写 <code>.card__body__button,而应:- 让
button本身是独立 Block(button) - 在卡片中使用
button--in-card这类 Modifier 表达上下文影响 - Modifier 名称聚焦行为/状态(
--small、--primary),而非位置(--inside-header是坏味道)
这样做既维持 Block 独立性,又通过 Modifier 承载组合逻辑,CSS 选择器也更可控——
.button--in-card比.card__body .button更明确、不易被意外覆盖。警惕 CSS-in-JS 或组件库自动注入导致的隐式嵌套
React/Vue 中用
styled-components或emotion时,容易无意识写出嵌套样式:const Card = styled.div` &__body { /* … */ } &__body &__button { /* 错!这等于生成 .card__body .card__button */ } `这类写法看似方便,实则破坏 BEM 的扁平约束,且生成的选择器权重高、调试困难。正确做法是:在 JSX 中显式写全类名
className="card__body"和className="button button--in-card",样式文件里只写单一级别的规则。真正难的不是写对名字,而是每次加一个
__前,停下来问一句:这个东西,真的属于当前 Block 的一部分,还是它早该自己站出来? - 让











