先从一个"惨案"说起
你是不是也经历过这样的场景:
你给按钮写了个
.btn样式,美滋滋。结果第二天,同事也在他的模块里写了个.btn,样式完全不一样。两个.btn在页面上相遇,CSS 层叠规则开始"打架",按钮变得四不像。你俩对着屏幕面面相觑------这锅到底谁的?
这就是 CSS 命名混乱的经典现场。而 BEM,就是来终结这场混乱的"和平条约"。
BEM 是什么?
BEM 是 Block(块)、Element(元素)、Modifier(修饰符) 三个单词的缩写,由俄罗斯 Yandex 公司提出,是一套 CSS 类名命名方法论。
它的核心思想很简单:把页面拆成独立的组件块,用一套统一的命名规则,让每个类名都能"自报家门"。
三个角色,各司其职
🧱 Block(块)------ 独立的组件
Block 是页面上独立、可复用的组件,它不依赖任何其他东西,自己就能活得很好。
.header { }
.menu { }
.button { }
.card { }
类比:Block 就像乐高积木里的一块"车轮",它自己就是完整的,不需要依附于谁。
👶 Element(元素)------ 块的组成部分
Element 是 Block 的子部件 ,离开了 Block 就没有意义。命名时用双下划线 __ 连接 Block 和 Element。
markdown
.menu__item { }
.card__title { }
.button__icon { }
.search-form__input { }
类比:
menu__item就是"菜单里的某一项",它生来就属于menu,单独拎出来没人知道它是干嘛的。
🎨 Modifier(修饰符)------ 状态或变体
Modifier 用来描述 Block 或 Element 的不同状态、外观或变体 。命名时用双连字符 -- 连接。
lua
.button--primary { }
.button--disabled { }
.menu__item--active { }
.card--dark { }
类比:
button--disabled就是"那个被禁用的按钮",它还是按钮,只是状态不一样。
完整公式一览
lua
.block { }
.block__element { }
.block--modifier { }
.block__element--modifier { }
记住这个公式,走遍天下都不怕。
实战演练:一个卡片组件
来看一个完整的例子:
ini
<div class="card card--featured">
<h2 class="card__title">精选商品</h2>
<p class="card__description">这是一段商品描述。</p>
<button class="card__button card__button--primary">立即购买</button>
</div>
css
/* Block */
.card {
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
/* Block Modifier */
.card--featured {
border-color: #ff6b6b;
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.2);
}
/* Elements */
.card__title {
font-size: 18px;
margin-bottom: 8px;
}
.card__description {
font-size: 14px;
color: #666;
}
.card__button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Element Modifier */
.card__button--primary {
background-color: #ff6b6b;
color: white;
}
看,光看类名你就能知道:
card是主体组件card__title是卡片里的标题card--featured是"精选版"卡片card__button--primary是卡片里那个主色调的按钮
类名自己会说话,不需要注释。
为什么 BEM 这么香?
| 优点 | 说明 |
|---|---|
| 避免样式冲突 | 每个类名都有唯一"户口",不会互相覆盖 |
| 自文档化 | 看类名就知道结构和关系,新人也能秒懂 |
| 高复用性 | Block 独立存在,随便拖到哪个页面都能用 |
| 团队协作友好 | 统一规则,不用猜别人的命名习惯 |
| 低特异性 | 全是单层类名选择器,没有深层嵌套,性能好、易覆盖 |
一些最佳实践
- 全小写 + 连字符分隔单词 :
search-form✅,searchForm❌ - 元素不再嵌套命名 :不要写
card__body__text,直接card__text就好 - 修饰符不能单独使用 :
card--dark必须和card一起出现在 HTML 中 - 避免深层 CSS 嵌套 :BEM 鼓励用类名直接定位,而不是
.card .body .text这种选择器 - 配合预处理器更舒服 :用 Sass 的
&可以少写很多重复前缀
css
.card {
padding: 20px;
&__title {
font-size: 18px;
}
&__button {
padding: 8px 16px;
&--primary {
background: #ff6b6b;
}
}
}
BEM 的"小缺点"
当然,BEM 也不是完美的:
- 类名偏长 :
navigation-menu__item--active写起来确实有点累 - HTML 略显冗余:一个元素可能要挂多个类名
- 不是银弹:对于超小型项目,可能有点"杀鸡用牛刀"
但总体来说,在团队协作和中大型项目中,BEM 带来的秩序感远远超过它带来的"打字成本" 。
写在最后
BEM 本质上是一种约定 。它不强制你做什么,只是告诉你:如果大家都能遵守同一套命名规则,CSS 的世界就会和平很多。
下次当你准备写一个 .btn 的时候,不妨想一想------它属于哪个 Block?它有没有特殊的 Modifier?想清楚这些,你的 CSS 代码就会从"一盘散沙"变成"训练有素的军队"。
命名是编程中最难的两件事之一,BEM 至少帮我们解决了一半。😉