使用 BEM 规范设置 CSS 类名

三葉Leaves Author

BEM 提供语义化和结构化的 CSS 类命名约定。它让你和你的团队成员仅通过阅读 class 名就能理解 HTML 结构和元素关系,虽然写起来可能比随意起的类名长,但是在大型、工程化项目,亦或者参与开源社区等需要和他人合作的项目中显得尤为重要。

BEM 是什么?

BEM 代表 Block (块)Element (元素)Modifier (修饰符)

它的核心思想是:把用户界面拆分成一个个独立的、可复用的“块”,从而使开发过程更加清晰和快速。

把它想象成搭乐高:

  • Block (块):一个完整的乐高积木,比如一个“2x4 的红色砖块”。它本身是有意义的,可以独立存在。
  • Element (元素):砖块上的“凸点”。它不能独立存在,必须依附于砖块才有意义。
  • Modifier (修饰符):砖块的“颜色”或“特殊状态”,比如“透明的”或者“夜光的”。它用来改变砖块的外观或状态。

BEM 的三个组成部分详解

1. Block (块)

定义:一个在功能上独立的、可复用的页面组件。它可以被放置在页面的任何地方。
命名:通常是一个或两个单词,描述其用途。
示例

  • 菜单: menu
  • 按钮: button
  • 搜索表单: search-form
  • 用户资料卡: profile-card

规则

  • 块的名称应该只描述它的“用途”,而不是它的“外观”。例如,用 error-message 而不是 red-text

2. Element (元素)

定义:块的一部分,不能脱离块独立使用。
命名:在块的名称后面加上两个下划线 __,再加上元素的名称。
语法block-name__element-name
示例

  • 菜单项: menu__item
  • 按钮图标: button__icon
  • 搜索输入框: search-form__input
  • 用户卡片里的头像: profile-card__avatar

规则

  • 元素永远是“块”的一部分,而不是“另一个元素”的一部分。即使 HTML 结构是嵌套的,BEM 命名也应该是扁平的,也就是只有一层。
    • 错误的做法: menu__item__text
    • 正确的做法: menu__text 。如果 textitem 的一部分,item 又是 menu 的一部分,那么 textitem 都是 menu 的元素:menu__itemmenu__text

3. Modifier (修饰符)

定义:一个用来定义块或元素的外观、状态或行为的“标志”。
命名:在块或元素的名称后面加上两个连字符 --,再加上修饰符的名称。
语法block-name--modifier-nameblock-name__element-name--modifier-name
示例

  • 一个被禁用的按钮: button--disabled
  • 一个“主要”状态的按钮: button--primary
  • 一个当前被选中的菜单项: menu__item--active
  • 一个特别推荐的用户卡片: profile-card--featured
  • 一个尺寸很大的搜索表单: search-form--large

规则

  • 修饰符不能单独使用,它必须依附于一个块或元素。
  • 通常在 HTML 中,我们会同时保留基础类和修饰符类。

实战演练:用 BEM 构建一个用户卡片组件

让我们来创建一个 UserProfileCard.vue 组件,并用 BEM 来命名它的样式。

组件结构设想:

  • 一个卡片容器 (Block)
  • 里面有一个头像 (Element)
  • 一个用户名 (Element)
  • 一段个人简介 (Element)
  • 一个关注按钮 (Element)
  • 我们还希望这个卡片有一个“精选”状态 (Modifier)
  • 按钮有“主要”和“次要”两种状态 (Modifier)

UserProfileCard.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<template>
<!--
Block: 'profile-card'
Modifier: 通过 isFeatured prop 动态添加 'profile-card--featured'
-->
<div class="profile-card" :class="{ 'profile-card--featured': isFeatured }">

<!-- Element: 'profile-card__avatar' -->
<img src="..." alt="User Avatar" class="profile-card__avatar" />

<!-- Element: 'profile-card__name' -->
<h3 class="profile-card__name">张三</h3>

<!-- Element: 'profile-card__bio' -->
<p class="profile-card__bio">
这是一段非常精彩的个人简介。
</p>

<!-- Element: 'profile-card__button' -->
<!-- Modifier: 'profile-card__button--primary' -->
<button class="profile-card__button profile-card__button--primary">
关注
</button>
</div>
</template>

<script setup>
defineProps({
isFeatured: Boolean
});
</script>

<style scoped>
/* 1. Block 的基础样式 */
.profile-card {
border: 1px solid #ccc;
border-radius: 8px;
padding: 20px;
text-align: center;
background-color: white;
transition: all 0.3s ease;
}

/* 2. Block 的 Modifier 样式 */
.profile-card--featured {
border-color: #ffc107;
box-shadow: 0 4px 15px rgba(255, 193, 7, 0.5);
}

/* 3. Elements 的样式 */
.profile-card__avatar {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
}

.profile-card__name {
margin: 15px 0 10px;
font-size: 1.5em;
color: #333;
}

.profile-card__bio {
font-size: 1em;
color: #666;
margin-bottom: 20px;
}

.profile-card__button {
padding: 10px 20px;
border: 1px solid #ddd;
background-color: #f0f0f0;
cursor: pointer;
border-radius: 5px;
font-weight: bold;
}

/* 4. Element 的 Modifier 样式 */
.profile-card__button--primary {
background-color: #007bff;
color: white;
border-color: #007bff;
}

.profile-card__button:hover {
opacity: 0.8;
}
</style>

BEM 与 Vue scoped 的关系

有人会问:“既然我用了 scoped,为什么还需要 BEM?”

它们是相辅相成的,解决了不同层面的问题:

  • scoped:提供技术层面的样式隔离。它通过添加 data-v-xxx 属性来防止组件间的样式冲突。这是机器做的事情。
  • BEM:提供语义化和结构化的命名约定。它让你和你的团队成员仅通过阅读 class 名就能理解 HTML 结构和元素关系。这是人脑需要的东西,是一种沟通工具

结合使用时,你会得到双重保障:既有机器保证的隔离性,又有人类可读的结构化代码。

BEM 的核心优势总结

  1. 避免样式冲突:由于类名足够具体,几乎不会与其他组件的样式冲突。
  2. 样式扁平化,低权重:BEM 鼓励你只使用单层类选择器,避免了 .card .header .title 这样的深度嵌套。这使得 CSS 权重(specificity)保持在很低的水平,非常容易覆盖和维护。
  3. 高度可复用:整个 profile-card 块可以被轻松地拿到任何项目中去使用。

开始使用 BEM 时,可能会觉得类名有点长,但它带来的清晰度和可维护性上的巨大提升,绝对是物超所值的。

记住核心规则:块__元素--修饰符,然后在一个新组件里尝试一下,你很快就会爱上它。

  • 标题: 使用 BEM 规范设置 CSS 类名
  • 作者: 三葉Leaves
  • 创建于 : 2025-06-25 00:00:00
  • 更新于 : 2025-07-10 13:40:50
  • 链接: https://blog.oksanye.com/e05952e914c0/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论