bem类名通过block__element--modifier结构将归属、角色、状态三重语义固化,实现“秒懂”式自解释;user-card__delete-btn因含行为动词和样式词而语义失真,应改为user-card__action--delete;card__header__title非法,因bem禁止element嵌套,须拆为同级card__header与card__title。

类名有没有意义,直接决定别人打开你的 CSS 文件时是“秒懂”还是“先翻 HTML 再查 JS 最后猜意图”。BEM 不是强制你写长名字,而是用 block__element--modifier 这种固定结构把「归属、角色、状态」三重信息焊死在类名里——不用注释,人眼一扫就还原出上下文。
为什么 user-card__delete-btn 看似合规实则危险
它暴露两个隐性问题:一是带行为动词 delete,把用途锁死在“删除”场景,后续复用为“移除收藏”或“取消关注”就语义失真;二是含样式词 btn,万一哪天改成文字链接或图标按钮,类名就彻底失效。
- 正确写法是
user-card__action--delete:Action 是稳定角色,delete 是可枚举状态,二者解耦,支持自由组合--edit、--share - Element 名必须回答“它在结构里起什么作用”,不是“它看起来像什么”或“点它会干什么”
- 一旦退化成动词+样式词的混合命名,BEM 的自解释能力立刻归零,团队又得靠注释和口头对齐来补位
card__header__title 为什么是非法命名
BEM 明确禁止 Element 嵌套。HTML 中 <div class="card__header">
<h2 class="card__title"> 才是合法结构——<code>card__header 和 card__title 都是 card 的直属子元素,不存在父子 Element 关系。
- 写成
card__header__title会让人误以为 title 是 header 的子内容,破坏 BEM 的层级契约 - 更隐蔽的问题是泛化命名,比如
card__content:content 是个筐,后期塞进图片、按钮、描述后,没人能单凭类名判断这个 class 到底管哪块 - 应按实际角色拆解:
card__image、card__body、card__footer
Sass 嵌套时怎么避免生成 .card.is-open__header 这种非法选择器
嵌套本身没问题,但修饰符(Modifier)不能通过 & 挂到 Element 上。Sass 编译器不校验 BEM 合法性,它只忠实地拼字符串。
- 错误写法:
.card { &__header { … } &.is-open { &__header { … } } }→ 输出.card.is-open__header,违反 BEM 规则 - 正确写法:修饰符只作用于 Block 或 Element 本身,例如
.card--expanded或.card__header--sticky - 用
stylelint-selector-bem-pattern插件做静态校验,比靠人眼盯更可靠
真正难的从来不是记住 __ 和 -- 的写法,而是让所有人对“什么是元素”达成一致——这需要在 CR 时盯住每一个新类名,而不是等上线后靠注释去打补丁。











