BEM是用block__element--modifier三段结构编码样式归属、层级与状态的命名规范。header__logo--dark明确标识所属块、元素及修饰态,避免logo-dark等模糊命名引发的歧义;禁止嵌套过深、跨块组合及修饰符与状态类混用,须通过工具链保障一致性。

BEM不是“加下划线的命名习惯”,而是用block__element--modifier三段结构把样式归属、层级、状态全部编码进类名本身——不看HTML也能判断作用域,不查JS也能识别状态来源。
为什么header__logo--dark比logo-dark更可靠
类名里没写header,你就永远不确定这个logo-dark是全局暗色logo,还是仅用于页头的变体。而header__logo--dark明确声明:它属于header块、是其logo子元素、当前启用dark修饰态。
- 常见错误现象:
.user-card-avatar或.avatar-user-card——分隔符缺失或顺序混乱,导致无法被stylelint-selector-bem-pattern校验,协作时要靠猜 - 模块名必须是独立功能单元:
card✅,section❌(太泛);user-profile✅(含短横可接受),但不能写成user-profile__avatar--large❌(--large应作用于user-profile或user-profile__avatar,不能跨层) - 性能影响极小,但语义错位会持续拖慢排查速度:审查元素看到
.btn-primary,你得点开HTML确认它是不是在.modal里被意外覆盖;而.button--primary直接告诉你——这是按钮组件自身的主色调变体
哪些情况该把__element升格为独立block
当某个子元素开始在多个上下文中复用,或具备独立交互逻辑时,它就不再是“子元素”,而是新组件。
- 使用场景:
.product-item__price-tag→ 如果price-tag同时出现在商品列表、购物车弹窗、订单详情页,且样式/行为一致,那就该拆成独立.price-tag块 - 判断依据:这个类是否会在其他DOM结构中出现?是否需要单独测试、文档化、或被其他团队引用?
- 嵌套过深即危险信号:
.card__content__header__title❌——BEM只允许一层__,多级意味着结构失控;应改为.card__title或另起.title块 - 禁止跨块组合:
header__button--submit❌——button是独立块,应写成button button--submit并由header容器控制布局
--modifier和is-状态类混用时怎么避免样式冲突
修饰符是设计静态变体(如尺寸、主题),状态类是运行时开关(如加载中、展开)。两者语义不同,混用会破坏样式隔离。
- 错误现象:
.button--primary.is-active和.button--secondary.is-active共享同一个.is-active { opacity: 0.5; },结果主按钮和次按钮激活态表现一样 - 推荐做法:状态类也绑定到块上,写成
.button.is-active而非全局.is-active;若需差异化,用.button--primary.is-active限定范围 - 参数差异:
button--small✅(尺寸修饰符),button--mobile❌(位置描述,违反BEM语义);is-loading✅(布尔状态),button--loading❌(混淆了修饰符与状态) - JS操作必须严格匹配:
el.classList.add('card__body--expanded')✅,el.classList.add('card__body' + '--' + state)❌(拼接易出错,且破坏静态分析)
Webpack/Vite项目里怎么让BEM不变成维护负担
纯手写容易漏掉__或打错--数量,尤其在动态类名场景。靠人工盯不如靠工具链约束。
- VS Code 可配
Auto Rename Tag+BEM Tools插件,输入card后按Tab自动补全card__和card-- - 构建阶段用
stylelint-selector-bem-pattern强制校验,CI里报错阻断提交,比Code Review发现早三天 - CSS-in-JS场景(如Emotion):用
css`...`配合模板字符串写button--primary,禁用className={`${base}--${variant}`这种运行时拼接 - 渐进式迁移关键点:老代码不重命名,但新增样式一律走BEM;修一个
.btn:hover时,顺手把对应DOM里的.btn改成.button及其子元素
最常被忽略的是修饰符的“单职责”:一个类名里出现--primary--large--disabled,不是BEM写得好,而是组件职责过载,该拆了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











