BEM 通过块__元素--修饰符命名法明确归属、层级和语义,避免样式冲突与维护困境;如 user-card__avatar 比 avatar 更可靠,因它锁定模块归属、结构层级和角色语义。

直接用 header-title 或 bigButton 这类名字写样式,后期改色、换布局、加新页面时,八成要重命名+改 HTML + 搜全项目找漏网之鱼。BEM 不是“多加几个横线显得专业”,而是把「谁、在哪、什么状态」这三个问题,硬编码进类名里,让样式不再靠猜、不靠上下文、不靠人脑记忆。
为什么 user-card__avatar 比 avatar 更可靠
因为 avatar 是裸奔的类名:它没说明属于哪个模块、是否可复用、有没有变体。一旦在 profile-page 和 comment-list 里都用了,样式就可能互相覆盖或漏匹配。user-card__avatar 则明确锁死三件事:
- 归属:只属于
user-card这个块,改它不影响team-member__avatar - 层级:是
user-card的直接子元素,不是嵌套在某个__header里的孙元素 - 语义:
__avatar描述的是结构角色(头像区域),不是外观(比如__circle-img)
常见错误是写成 user-card-avatar(少双下划线)或 user-card__avatar--round(但 --round 是视觉描述,应改为 --circular 或统一用 CSS 变量控制形状)。
button--disabled 能用,button--red 不能用
修饰符(--xxx)必须表达可预测、可开关的状态或角色,而不是具体样式值。JS 控制 button--disabled 的增删是自然的;但 button--red 一旦品牌色改成紫色,就得全局搜替换,还可能误伤其他 “red” 字眼。
- ✅ 正确:
button--primary、input--expanded、modal--fullscreen - ❌ 错误:
button--bg-red、card--w-300px、text--14px - 性能影响几乎为零,但语义错位会导致组件无法主题化——暗色模式切换时,
--primary可由 CSS 变量统一接管,--red只能硬编码重写
SCSS 里怎么写才不破坏 BEM 结构
用 &__element 和 &--modifier 是安全的,但只要出现空格或标签选择器,就等于悄悄绕开 BEM 约束。
- ✅ 安全写法:
.button { &__icon { margin-left: 8px; } &--disabled { opacity: 0.5; } } - ❌ 危险写法:
.button { &__content { p { color: #333; } // p 是标签选择器,违反 BEM “只用类名” 原则 } } - 遇到伪类(如
:hover),别写&:hover,而要用&--hover配合 JS 切换,否则无法响应键盘焦点或媒体查询变化
React 里用 clsx 拼 card__body card__body--expanded 时容易漏什么
最常漏的是基础块类(card)本身。只写 card__body,等于把元素当成了独立块,破坏了 BEM 的作用域链。
- ✅ 正确:
className={clsx('card', 'card__body', isExpanded && 'card__body--expanded')} - ❌ 错误:
className={clsx('card__body', 'card__body--expanded')}(缺card,CSS 里无法用.card__body独立生效) - 更隐蔽的坑:把 Modifier 写进条件逻辑太深,比如
isDisabled && 'button--disabled'分散在多个 JSX 行里,后期加--loading就得再补一串,建议抽成对象映射或用useBem自定义 Hook 统一管理
真正卡点不在规则多难记,而在所有工具链没对齐:VS Code 缺插件提示、stylelint 没开 selector-bem-pattern、CI 不校验新增类名——这时候 BEM 就只是文档里的一行字,不是代码里的约束力。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











