CSS - BEM 命名规范

传统的 CSS 是没有命名空间(作用域)这一概念的,当页面模块过多时容易引起样式冲突,这时候可以为样式名称添加 前缀后缀 来解决。

BEM 便是一套广为流传的命名约定,旨在规范化 CSS 样式名称,便于阅读和编写,以及团队协作。

规范定义

BEMBlock(块)Element(元素)Modifier(修饰符)的缩写,顾名思义,整套命名规范就是基于这三部分进行组合的。

词组

Block(块)

块是指具有独立意义的独立实体,也就是页面中的一些独立模块。例如:navbararticletocmenu

Element(元素)

元素是指块的一部分,没有独立的意义,并且在语义上与其块相关。例如:titlecontentiteminfo

Modifier(修饰符)

修饰符是指块或元素上的标志,使用它们可以更改外观或行为。例如:disabledcheckedsuccessprimary

BEM - 图示

如上图,红色部分是块,绿色部分是元素,蓝色部分是修饰符。

连接符

__(双下划线)

双下划线用来连接 元素 。例如:article__titlearticle__contentarticle__item

– (双中划线)

双中划线用来连接 元素修饰符。例如:button--disabledform--primarytoc--active

-(中划线)

中划线用来连接 字符,块、元素、修饰符中均可使用。例如:order-formprogress-bartheme-dark

举个栗子

组合上述部分进行命名即可,例如通常我们是这么命名的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 传统命名 -->
<article class="article">
<div class="head">
<h1 class="title">CSS - BEM 命名规范</h1>
<div class="info">
<span>时间:十一月 16, 2020</span>
<span>访客:666</span>
</div>
</div>
<div class="content">
<code class="code">
...
</code>
...
</div>
</article>

换成 BEM 就可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- REM 命名 -->
<article class="article">
<div class="article__head">
<h1 class="article__title">CSS - BEM 命名规范</h1>
<div class="article__info">
<span>时间:十一月 16, 2020</span>
<span>访客:666</span>
</div>
</div>
<div class="article__content">
<code class="article__code--highlight">
...
</code>
...
</div>
</article>

一些建议

配合 CSS 预处理器使用

BEM 最大的诟病是书写太麻烦了,每个样式都像一长串蚂蚁,真是简(you)洁(chou)明(you)了(chang)呢。

SassLessStylusCSS 预处理器大行其道的现在,配合 &(拼接符) 使用会相对简单,如下:

1
2
3
4
5
6
7
8
/* Stylus + BEM 编译前 */
.article
&__head
&__title
&__info
&__content
&__code
&--highlight
1
2
3
4
5
6
7
/* Stylus + BEM 编译后 */
.article__head {}
.article__title {}
.article__info {}
.article__content {}
.article__code {}
.article__code--highlight {}

其实在使用 CSS 预处理器时本身就具备了 作用域 的功能,最大的痛点解决了,使用 BEM duck 不必。存在即合理,BEM 还是有它的用武之地的。

先来看看传统的 CSS 预处理代码。

BEM 的优势有以下方面:

1
2
3
4
5
6
7
8
/* 传统 Stylus 编译前 */
.article
.head
.title
.info
.content
.code
&.highlight
1
2
3
4
5
6
7
8
/* 传统 Stylus 编译后 */
.article {}
.article .head {}
.article .head .title {}
.article .head .info {}
.article .content {}
.article .content .code {}
.article .content .code.highlight {}

性能

可以看到传统 Stylus 编译后的 CSS 样式中,选择器存在大量堆叠。而 CSS 引擎查找样式表时是根据 从左到右 的顺序去匹配规则的,这样就会浪费很多的查询性能,且开销随着嵌套层数呈几何级数递增。但是采用 BEM + Stylus 的写法一般就生成一条选择器样式,只需查询一次,做到 “指哪打哪”。

语义化

前面说到传统 Stylus 编译结果中存在大量重复嵌套,在 debug 时也是不直观的。而 BEM + Stylus 编译生成后则一目了然。

减少连接层数

BEM 本就麻烦,还要连接个几层,年轻人耗子尾汁。

  • block__element--modifier => 一只蚂蚁,一个头,一个身子,一个屁股。
  • block__block__element_element--modifier--modifier => 一只蚂蚁,许多头,许多身子,许多屁股。

B + E + M 足矣,没有 nB + nE +nM 这样的写法。必须对页面元素进行扁平化,抽象到只有一层结构。

恰当使用

在编写页面级组件时可以使用传统写法,毕竟无需多次复用;在编写全局组件时使用 BEM 规范,约定俗成便于团队维护。

最后:BEM 看着太难受了,我一般不用。

参考资料

Introduction - BEM — Block Element Modifier

查看评论