bem合规的html class必须与dom结构严格一一对应,card__title须为card直系子元素,禁止隔层或嵌套element;modifier须与基础class共存,如button button--loading;独立可复用节点应升格为block而非硬写为element。

直接说结论:BEM不是加几个下划线就完事,它生效的前提是类名与DOM结构严格一一对应;写错一个层级或混用block边界,样式就会“看起来对、实际不可维护”。
HTML里怎么写class才算合规BEM
BEM的class必须反映真实DOM嵌套关系,不能靠CSS选择器“补救”。比如card__title必须是card的直接子元素,中间不能隔一层div。
- 正确:
<article class="card"><h3 class="card__title">标题</h3></article> - 错误:
<article class="card"><div><h3 class="card__title">标题</h3></div></article>(card__title不是card的直系子节点) - 禁止出现
card__content__title——BEM不允许element嵌套element - modifier必须和基础class共存:
class="button button--loading",不能只写button--loading
遇到“这个东西既像element又像独立block”怎么办
判断标准不是它在页面里“看起来属于谁”,而是它能否脱离当前上下文单独存在、配置、测试。
- 如果图标只服务于按钮内部逻辑(比如加载状态图标),且从不复用到其他组件,才可命名为
button__loader - 如果同一个图标出现在header、footer、card多个地方,它就是独立block,应叫
icon或logo,而不是header__logo - 常见翻车点:把
user-card__avatar硬写死,结果头像组件要单独抽离成通用组件时,类名语义全崩
CSS里哪些写法会悄悄破坏BEM约束
BEM要求所有样式绑定到明确类名,禁用依赖上下文的选择器。Sass嵌套容易踩坑。
- 允许:
.card { &__title { font-size: 1.2em; } }(编译后仍是扁平类名) - 禁止:
.card { &__content { p { color: #333; } } }(p是标签选择器,破坏BEM“只用类名”原则) - 禁止:
.card .card__title(冗余嵌套,BEM类名自带作用域) - 禁止用
@extend跨block复用,比如@extend .button在.card__action里——会把button类注入,污染作用域
Vue/React里写BEM最容易忽略的细节
框架模板里class动态拼接时,block名必须随组件名一致,否则BEM结构就断了。
- Vue中不要硬编码
class="search-bar",而应从name或props.blockName生成,确保父组件传block-name="filter-panel"时,内部元素自动变成filter-panel__input - React中避免
className={`btn ${isLoading ? 'btn--loading' : ''}`这种拼接——漏掉基础btn类,modifier就失效 - 不建议用PostCSS插件自动生成BEM类名,结构一调,生成的类名就脱离语义,调试时根本看不出是谁的element
真正卡住人的从来不是语法格式,而是每次加新元素时,得停下来想清楚:“它到底属于谁?能不能被别人拿走用?”——这个判断过程没法自动化,也绕不开。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











