<p>BEM 通过将归属、层级、状态编码进类名(如 .user-cardavatar)解决样式冲突,杜绝后代选择器与手拼 class 风险,要求 SCSS 仅用 & 和 &-- 保持扁平结构,强调每次书写前思考样式归属。</p>

直接用 .button 或 .header 这类泛化类名,在中大型项目里一定会出样式冲突——BEM 不是让名字变长,而是把“归属、层级、状态”全锁进类名里,让冲突从随机覆盖变成结构错误,一眼可查。
为什么 .button 会覆盖 .user-card__avatar
浏览器不认“谁写的”,只按层叠顺序和选择器权重匹配。只要两个文件都定义了 .button,后加载的就生效;而 .user-card__avatar 和 .profile-card__avatar 天然不同名,哪怕共用同一份 CSS 文件也不会互相干扰。
-
.card .title是错误写法:DOM 加个 wrapper 就失效;正确是.card__title,不依赖父级结构 -
.button--primary缺少 block 前缀,不是合法 BEM 类名;应为checkout-button--primary或search-form__submit--primary -
.search-form__input_error用单下划线,违反语法契约;必须是--error,否则工具链(如 stylelint-selector-bem-pattern)无法识别
SCSS 里怎么写才不破坏 BEM 扁平结构
BEM 要求最终生成的 CSS 类名是扁平的(如 .user-card__avatar),不能靠 DOM 层级匹配。SCSS 嵌套本身没问题,但空格嵌套会产出后代选择器,破坏封装性。
- 错误写法:
.user-card { .avatar { } }→ 编译出.user-card .avatar,无法从类名反推来源 - 正确写法只用
&__和&--:.user-card { &__avatar { } &--loading { } } - 禁止
&__avatar { &__icon { } }:BEM 不允许__嵌套;真需要图标变体,用.user-card__avatar--with-icon
JS 动态拼接 className 容易踩哪些坑
手拼字符串看着快,实际极易漏空格、错连字符、大小写混用,本地跑得通,CI 上直接挂。
立即学习“前端免费学习笔记(深入)”;
- 危险写法:
className={`button button--${variant} ${hasIcon ? 'button__icon' : ''}`}—— 缺空格、button__icon脱离 block、无防错 - 推荐封装常量:
const BLOCK = 'search-form'; const cn = (e, m) => `${BLOCK}${e ? '__' + e : ''}${m ? '--' + m : ''}`,调用cn('input', 'disabled')得到search-form__input--disabled - 若用 CSS Modules,坚持
import styles from './Button.module.css'+className={styles['button--loading']},永远不硬写哈希类名
最容易被忽略的不是怎么写 BEM,而是每次写 class 前是否真问过:“这个样式属于谁?它会不会在别的上下文里意外生效?”——这句话比任何工具配置都管用。


















