BEM中Block是独立可复用的功能模块(如.card),Element是其必须依附存在的组成部分(如.card__title),Modifier是描述状态或变体的修饰符(如.card--large),三者共同构成语义清晰、作用域隔离的命名体系。

什么是BEM里的block、element和modifier
BEM不是语法糖,而是把组件结构显式编码进类名的约定。一个block是独立可复用的模块(比如header或card),element是它内部的子部分(如card__title),modifier是变体状态(如card--large)。关键在于:元素必须依附于块,不能脱离上下文存在;修饰符只改变外观,不改变结构。
常见错误是把语义标签当块名:div class="article"看着像块,但article是HTML语义标签,不是业务组件——真正该命名的是你封装的卡片组件,比如post-card。
怎么写才不会让HTML变得又长又难读
类名长度确实会上升,但换来的是可维护性。核心策略是控制层级深度和命名粒度:
- 一个
block只对应一个功能区域,不要嵌套过深的element,比如避免form__input__label__text这种三层嵌套,应拆成form__input+form__label -
element名用名词,不用动词或形容词(button__icon✅,button__clickable❌) -
modifier必须和block或element一起出现,单独写btn--primary无效,得是btn btn--primary或btn__text btn__text--bold - 避免“过度BEM化”:纯布局容器(如仅用于
display: flex的包裹层)可不加BEM类,用div或语义标签即可
遇到React/Vue组件时怎么适配BEM
框架组件天然适合BEM,因为每个组件就是一个block。关键是把BEM逻辑从模板里“提出来”,而不是在JSX中拼接字符串。
立即学习“前端免费学习笔记(深入)”;
比如Vue中,别这么写:<div :class="`card card--${size} card__header`">。应该用计算属性或工具函数生成完整类名:
computed: {
cardHeaderClass() {
return ['card__header', this.isCompact ? 'card__header--compact' : '']
}
}
React中推荐用clsx库:className={clsx('card', `card--${size}`, {'card--disabled': isDisabled})}。重点是:修饰符状态必须显式声明,不能靠CSS选择器推导(比如.card.disabled .card__header就违背BEM原则)。
为什么card__title--highlighted比card__title highlighted更可靠
前者把上下文锁死在card内,后者依赖外部类名组合,容易被全局样式污染或误匹配。BEM的连字符分隔(__和--)不是为了好看,而是让类名具备机器可解析性——能用正则快速提取块名、区分元素与修饰符。
真实踩坑点:团队有人用card-title(短横线)代替card__title,导致CSS预处理器无法用@at-root正确嵌套,也破坏了BEM工具链(如stylelint插件)的识别逻辑。只要用BEM,就必须严格遵守双下划线/双短横线规则。
最常被忽略的是命名一致性:同一个块里,card__image和card__img混用,会让维护者无法判断这是两个元素还是笔误。BEM干净与否,80%取决于是否坚持命名字典。



















