CSS编写策略之BEM

项目开发过程中,一套合适的开发风格指南能够有效提高实际开发速度,降低维护成本。然而在有些项目开发过程中,CSS并没有完善的结构或者遵循命名约定,这导致在项目迭代的过程中,CSS结构变得越来越冗余,既降低了开发效率也影响性能。

现有的CSS编写策略有很多,如OOCSS,SMACSS,SUIT CSS等等,今天我们要介绍的其中一种——BEM。

什么是BEM

BEM是Block,Element,Modifier的首字母缩写。是一种CSS的命名规范。定义了CSS中class的命名规则,如.b-blockname__element_name--modifier-name。其中以b-开头的原因稍后会解释。

Block 代表一个完整独立的实体

试想一下js中的组件,我们将一种特定可复用的结构封装成组件,然后我们可以在任何需要的地方使用该组件标签占位,然后就能将一大段复杂结构应用到该地方。

BEM中的block也是类似的原理,Design中的某些设计元素可以被用在多个地方,就可以把这个设计元素的样式提取成一个独立的块,而这个块的名字就是.b-blockname__element-name--modifier-nameblockname的部分。对于class命名来说,这个block就相当于命名空间

举个例子:


//html

  

title

body content

弹窗可以作为网页设计中一个独立元素,所以我们可以把独属于它的样式单独提出来封装到一个css样式块,这个块的class命名中blockname的部分就是popup

Element 代表Block里的局部元素

Element指代存在于某个特定block块内部的元素,它可以是block中任意的某个DOM节点。以上面popup的代码为例,h1就是一个element,而我们在给它的class命名中以b-popup-modal__title中的__title来表示BEM规则中E的部分。

Modifiers标示了同一个Blcok/Element不同状态下的不同样式

Modifier可以概括为一种状态标志,对于同一个Block/Element可能有一种基础样式,但是在不同的状态下会呈现出另一种样式,这种所谓的状态就可以通过命名modifier来区分。以上面代码中的.b-btn--disable为例,--disable就是一个modifier,同样的--primary, --default也是一种modifier。通过定义这样不同的modifier,我们可以很容易估计某个元素会有什么样式或者处于什么状态。

需要注意的是,所以我们可以单独定义一个block作为class,但element和modifier都是和block绑定的非独立模块,block是他们的命名空间,所以element/modifier一定是和block绑定出现的。

使用BEM编写CSS

在了解了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

说了这么多之后,最核心的问题还是为什么要使用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的准确定义。

参考资料
  • Get BEM

你可能感兴趣的:(CSS编写策略之BEM)