转载必须标明出处,谢谢。文章有疏漏浅薄之处,欢迎各位大神指正css
项目开发过程当中,一套合适的开发风格指南可以有效提升实际开发速度,下降维护成本。然而在有些项目开发过程当中,CSS并无完善的结构或者遵循命名约定,这致使在项目迭代的过程当中,CSS结构变得愈来愈冗余,既下降了开发效率也影响性能。html
现有的CSS编写策略有不少,如OOCSS,SMACSS,SUIT CSS等等,今天咱们要介绍的其中一种——BEM。bash
BEM是Block,Element,Modifier的首字母缩写。是一种CSS的命名规范。定义了CSS中class的命名规则,如.b-blockname__element_name--modifier-name
。其中以b-
开头的缘由稍后会解释。模块化
试想一下js中的组件,咱们将一种特定可复用的结构封装成组件,而后咱们能够在任何须要的地方使用该组件标签占位,而后就能将一大段复杂结构应用到该地方。性能
BEM中的block也是相似的原理,Design中的某些设计元素能够被用在多个地方,就能够把这个设计元素的样式提取成一个独立的块,而这个块的名字就是.b-blockname__element-name--modifier-name
中blockname
的部分。对于class命名来讲,这个block就至关于命名空间。spa
举个例子:设计
//html
<div class="b-popup-modal">
<h1 class="b-popup-modal__title">title</h1>
<div class="b-popup-modal__body">
body content
</div>
<div class="b-popup-modal__footer">
<button class="b-btn b-btn--primary b-btn--disable">Submit</button>
<button class="b-btn b-btn--default">Cancel</button>
</div>
</div>
复制代码
弹窗能够做为网页设计中一个独立元素,因此咱们能够把独属于它的样式单独提出来封装到一个css样式块,这个块的class命名中blockname的部分就是popup
。code
Element指代存在于某个特定block块内部的元素,它能够是block中任意的某个DOM节点。以上面popup的代码为例,h1
就是一个element,而咱们在给它的class命名中以b-popup-modal__title
中的__title
来表示BEM规则中E的部分。orm
Modifier能够归纳为一种状态标志,对于同一个Block/Element可能有一种基础样式,可是在不一样的状态下会呈现出另外一种样式,这种所谓的状态就能够经过命名modifier来区分。以上面代码中的.b-btn--disable
为例,--disable
就是一个modifier,一样的--primary
, --default
也是一种modifier。经过定义这样不一样的modifier,咱们能够很容易估计某个元素会有什么样式或者处于什么状态。htm
须要注意的是,因此咱们能够单独定义一个block做为class,但element和modifier都是和block绑定的非独立模块,block是他们的命名空间,因此element/modifier必定是和block绑定出现的。
在了解了BEM的基本原理后,接下来再具体说一下它的实现方法。上面已经说到BEM其实是一种命名规范,在css里就是指class的命名规范。具体实现规则团队能够根据本身的需求作些微调,但原理都离不开block,element和modifier三部分。如下提供一种通用规则做为参考:
Block,element和modifier名字能够包含字母,数字,下划线(_)和短横杠(-),其中-
能够做为单词分隔符代替驼峰式命名方式(不采用驼峰式命名的缘由是这里html中大小写不敏感)。
Block的命名能够以b-
开头,由于一个网页中不是全部的元素都须要被定义成block,b-
开头能够区分block和普通css class的区别。例如上面提到的.b-popup-modal
, .b-btn
。
用双下划线(__)来指示接下来是一个element名字,例如上面b-popup-modal__title
中的__title
。一样的还有__body
, __footer
。
经过双短横杠(--)来指示modifier的名字。
不是每个Block/Element都须要定义Modifier,这彻底取决于实际需求。
modifier的位置既能够在block后面,也能够跟在element后面。例如.b-btn--disable
, .b-nav__nav-item--visited
。
对于跟在block后的modifier,后面也能够再追加element,如.b-btn--disable__icon
。
说了这么多以后,最核心的问题仍是为何要使用BEM,它有什么好?
更语意化,可读性更强
经过双下划线(__), 双横杠(--) 等符号代码维护者能够轻松理解每一部分的意义,更强的可读性每每意味着更低的维护成本。
模块化,减小层叠带来的样式覆盖的问题
Block是彻底独立的存在,其内部的element/modifier的样式都在这个block的命名空间下书写的,因此不会收到其余外部样式的影响,不存在样式覆盖的问题。
.b-popup-modal {
//...
}
.b-popup-modal__title {
//...
}
复制代码
以上面代码为例,不管是block自己或者block内部element/modifier,都是针对单个class写样式,不须要使用复杂的css选择器(.b-popup-modal > .b-popup-modal__title
),最大程度地避免了权重计算。去除掉继承关系,css权重的影响,以block来分的模块化反而体现得更明显。
加强样式的重用性
就像js组合不一样的组件获得更复杂的组件同样,咱们也能够经过组合不一样的block获得更复杂的样式,例如使用.b-btn
, .b-input
来组合一个简单的form样式,从而提升代码的可复用性,从另外一方面讲也是下降了维护成本。
更容易作项目迁移
由于block样式是相对独立的,若是在其余项目有须要,咱们彻底能够讲某个单独的block相关的样式应用到其余项目中。
综上所诉BEM的特色和用法,经过遵循这样一种命名规范确实可以帮助项目维护一套更易懂,维护成本相对更低,更容易扩展的CSS代码库。
可是一个项目里不是全部的样式都要作成block。相比于BEM的用法,我的以为更难的实际上是如何精确划分好每个block以及对各类modifier的准肯定义。