BEM不是让class名变长,而是用block__element--modifier将归属、层级、状态锁进类名,避免冲突;直接写.btn或.header必然出事,因浏览器只按字符串匹配和权重生效,多处定义易覆盖且不敢删旧类。

BEM 不是让 class 名变长,而是用 block__element--modifier 把“谁的、什么、在什么状态”全锁死在字符串里——只要写对,天然不冲突。
为什么直接写 .btn 或 .header 必然出事
浏览器不认语义,只比类名字符串是否一致、选择器权重是否更高。.btn 在 header、modal、form 里各定义一次,谁生效取决于加载顺序和有没有 !important,不是你写的早就有优先权。更麻烦的是:没人敢删旧 .btn,怕误伤别人页面。
- 常见错误现象:
.card在 A 模块设了padding: 16px,B 模块又加了margin: 8px,结果侧边栏菜单跟着撑开 - 所有组件级样式必须带明确上下文前缀,比如
.user-profile__avatar、.search-form__submit - 禁止纯功能类名(如
.red、.mt-16),它们无法表达归属,也拦不住别人复用时误用
__ 和 -- 到底怎么分,写错一个字符就失效
BEM 的三段式不是格式要求,是语义协议:__ 表示“这个元素属于且仅属于该 block”,-- 表示“这个 block 或 element 当前处于某种可预期的状态”。少一段,语义就断档。
-
menu__item--active合法:menu 是 block,item 是其子元素,active 是 item 的状态 -
menu_item--active❌ 缺少双下划线,预处理器或构建工具可能忽略;CSS 选择器根本匹配不上 -
btn--disabled✅ 正确:disabled 是 btn 的状态,必须和btn共存,否则基础边框、颜色等可能丢失 -
btn__disabled❌ 错把 modifier 当 element,违反 BEM 层级规则
SCSS 里嵌套写法怎么不破坏 BEM 扁平结构
SCSS 嵌套本身没问题,危险的是嵌套出后代选择器——它会让 CSS 失去封装性,且无法从类名反推来源。
立即学习“前端免费学习笔记(深入)”;
- 错误写法:
.user-card { .avatar { ... } }→ 编译出.user-card .avatar,依赖 DOM 层级,HTML 加个 wrapper 就失效 - 正确写法只用
&__和&--:.user-card { &__avatar { ... } &--loading { ... } }→ 输出扁平类名.user-card__avatar - 禁止
&__avatar { &__icon { ... } }:BEM 不允许 element 嵌套 element,user-card__avatar__icon是非法结构 - 真需要图标变体?用
user-card__avatar--with-icon,而不是新增一层 __icon
第三方组件引入时,BEM 怎么守住边界不被污染
BEM 不改变第三方类名,但能帮你划清责任边界。你无法控制 .ant-btn,但可以控制它的使用上下文。
- 必须包一层 wrapper block:
<div class="myapp-form-field--date"><DatePicker /></div> - CSS 中限定作用范围:
.myapp-form-field--date .ant-date-picker,而非全局写.ant-date-picker { ... } - 禁用
!important覆盖第三方样式——它会切断 BEM 的 modifier 覆盖链,比如btn--primary本该覆盖btn的颜色,却被外部!important截断 - 构建阶段可用
postcss-prefix-selector统一加业务前缀(如myapp-),比手写myapp-search-form__input更可靠,也不破坏第三方选择器链
最常被忽略的一点:BEM 不是字符串格式规范,而是组件边界协议。写错类名,往往意味着 DOM 结构没想清、职责没划好——这时候修 CSS 不如先重画组件图。



















