1. 什么是BEM?
BEM是由Yandex公司推出的一套CSS命名规范,官方是这么描述它的:
BEM是一种让你可以快速开发网站并对此进行多年维护的技术。
一开始,Yandex公司推出的BEM,包括了规范以及其配套构建工具。如今提到的BEM主要是指其中的规范,在BEM最新的推广页中,对其的描述为:
BEM是一种命名方法,能够帮助你在前端开发中实现可复用的组件和代码共享。
2. BEM 命名规范
BEM就是块(block)、元素(element)、修饰符(modifier)的缩写,利用不同的区块,功能及样式来给元素命名。
BEM 命名约定模式
- B:(block)具有自身意义的独立实体。
可以是一个块级元素,可以理解为组件块,比如头部是个block,内容也是block,一个block可能由几个子block组成。例子
header
container
menu
checkbox
input
等
- E:(element)块的一部分,没有独立的含义,并且在语义上与其块相关联。
element是block的一部分,完成某种功能,element依赖于block,比如在logo中,img是logo的一个element,在菜单中,菜单项是菜单的一个element。
- M:(modeifier)块或元素上的标志。使用它们来更改外观或行为。
modifier代表block的不同状态或不同版本。比如
active
on
等
上面介绍了BEM分别是什么,那我们该如何连接他们呢?
.block { }
.block__element { }
.block--modifier{ }
其中
- block 代表了更高级别的抽象或组件。
- block__element 代表.block的后代,用于形成一个完整的.block的整体。
- block–modifier代表.block的不同状态或不同版本。
下面我们来看个例子:
weui-primary_loading__dot:库名-组件_状态__元素名
库名:一般是各公司约定俗成的项目名或公司名。这里代表微信。
组件:一般用来创建单独的css来修饰特定的标签。
状态:一般以标签处于的状态或者可以进行交互的效果命名,这个例子可以表示正在加载中状态的样式
元素名:一般以标签作用描述命名。
3. BEM命名的好处
- BEM的关键是光凭名字就可以告诉其他开发者某个标记是用来干什么的。 通过浏览HTML代码中的class属性,你就能够明白模块之间是如何关联的:有一些仅仅是组件,有一些则是这些组件的子孙或者是元素,还有一些是组件的其他形态或者是修饰符。
- 更加模块化。 块样式永远不依赖于页面上的其他元素,因此你不会遇到级联问题。你还可以将已完成项目中的块转移到新项目。
- 具有可重用性。 以不同方式组合独立块,并智能地重用它们,减少了你必须维护的CSS代码量。有了一套样式指南,你可以构建一个块库,使你的CSS超级有效。
4. 项目实战-淘宝订单
说了这么多,让我们自己动手来实践一下,用前面介绍到了BEM命名法来写一下淘宝订单结构吧~
首先我们来分析一下:
- 这整个功能模块是淘宝页面的一小个功能部分,所以我们可以把这整个功能模块看作一个块(block),我们给他起名叫:
tb-order
- 在这整个块里分上下两个部分(element),上部分我们起名为:
tb-order__hd
;下部分叫:tb-order__bd
- 在下面的部分中,分为5个小部分,我们给他起名为:
tb-order__item
;这每个小部分中都有一个小圆点的元素,代表着当前各个页面情况的一个数量,比如待评价数量是2。我们在这给他起名:tb__pointer
;当它有数量的时候才进行显示,这时我们给他添加上状态(modefier):tb__pointer_on
分析到这,下面我们开始上代码:
<div class="tb-order">
<div class="tb-order__hd">
<span class="tb__title">我的订单</span>
<span class="tb__more">全部 ></span>
</div>
<div class="tb-order__bd">
<a href="#" class="tb-order__item">
<span>
<span class="iconfont icon-31daifukuan"></span>
<span class="tb__pointer"></span>
</span>
<p class="tb__desc">待付款</p>
</a>
<a href="#" class="tb-order__item">
<span>
<span class="iconfont icon-daifahuo"></span>
<span class="tb__pointer"></span>
</span>
<p class="tb__desc">待发货</p>
</a>
<a href="#" class="tb-order__item">
<span>
<span class="iconfont icon-31daishouhuo"></span>
<span class="tb__pointer tb__pointer_on">2</span>
</span>
<p class="tb__desc">待收货</p>
</a>
<a href="#" class="tb-order__item">
<span>
<span class="iconfont icon-xiaoxi"></span>
<span class="tb__pointer tb__pointer_on">8</span>
</span>
<p class="tb__desc">待评价</p>
</a>
<a href="#" class="tb-order__item">
<span>
<span class="iconfont icon-tuikuantuihuo"></span>
<span class="tb__pointer"></span>
</span>
<p class="tb__desc">退款/售后</p>
</a>
</div>
</div>
接下来完成css样式:
*{
margin:0;
padding: 0;
}
a{
text-decoration: none;
}
body{
background-color: #5b80d7;
letter-spacing: 1px;
}
.tb-order{
width:95%;
margin:10px auto;
background-color: white;
border-radius: 20px;
}
.tb-order__hd{
height:63px;
padding:0 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.tb__title{
font-size: 20px;
font-weight:bold;
/* line-height:63px; */
}
.tb__more{
font-size:16px;
color:gray;
}
.tb-order__bd{
height:84px;
display: flex;
justify-content: space-around;
}
.tb-order__item{
width:20%;
text-align: center;
line-height:2em;
color:black;
position: relative;
}
.iconfont{
font-size: 30px;
font-weight: 550;
}
.tb__desc{
font-size: 14px;
}
.tb__pointer{
width:22px;
height:22px;
position: absolute;
display: inline-block;
color:white;
top:-9px;
right:18px;
border-radius: 50%;
line-height: 22px;
font-size:11px;
font-weight: 550;
}
.tb__pointer_on{
background-color: #ff7302;
}
最后外面做出来的结果就是这样子啦:
上图图标皆来自阿里图标库: iconfont-阿里巴巴矢量图标库
使用方式为下载代码方法,从上面网址下载。然后将其以css方式引入,使用类名进行添加。
5. 个人总结
- 在学习BEM之前,我给每个组件起名都是基于对应的英文,写完html之后在添加css样式的时候就会有一种比较混乱的感觉。使用BEM之后感觉层次关系清晰了很多,我可以通过类名知道两个class之间的关系,另外还增加了代码的可复用性,减少了许多代码量。
- 使用BEM起名可能会导致我们输入很长的文本(大部分编辑器都有自动补全功能,而且gzip压缩将会让我们消除对文件体积的担忧),但是它依旧强大。并且对于某些在该块(block)中是唯一存在的元素时,我们可以省略一些写它。比如上面例子中,在
tb-order__hd
内部有一个标题元素,它在整个模块中是唯一的,所以我们可以直接写成tb__title