不是所有的问题依靠使用工具都能完美解决,软件的参与者不是工具而是人。
工程师之间怎样合作与配合,同样很重要。
编码约定,流程规范或者开发方法论,都有各自的作用。
BEM是一套前端开发方法论。
BEM methodology was invented at Yandex to develop sites which should be launched fast and supported for a long time. It helps to create extendable and reusable interface components.
如何重用代码,如何避免复制粘贴,如何降低复杂度,如何重构,如何书写自文档化的代码?
当大家都按照同样的开发方法去建构软件时,这些代码层面的问题都逐渐消除了。
按相同规则写的代码更容易达到一致,能提高生产力,让团队合作更默契。
它适合于所有的编程语言和框架。
1. BEM entity
Web开发中使用了各种技术,用了不同的语言,HTML,CSS,JavaScript等等。
BEM使用了统一的术语Block,Element和Modifier来描述它们。
Block,Element,Modifier统称为BEM entity.
(1)Block
Block是逻辑独立的页面单元,Block可以包含在其他Block中。
Block具有整体可移动性,且容易被复用。
(2)Element
Element用来构成Block,不能在Block外使用。
(3)Modifier
Modifier用来定义Block或Element的表现形式或者行为。
两个相同的Block使用了不同的Modifier可能看起来不一样。
注:
Block是一个整体性的概念,它的不同侧面可以由不同的技术实现。例如:
行为:JavaScript,CoffeeScript
表现:CSS,Stylus,Sass
模板:BEMHTML,BH,Pug,Handlebars,XSL
文档:Markdown,Wiki,XML
2. Block redefinition & Redefinition level
BEM核心概念中还提到了设计原则。
Block的最终实现通常会被划分成不同的层次(redefinition level),
每个更具体的层次,扩展或者覆盖上一层次对Block的实现。
Block的不同侧面的实现方式都可以按层次进行设计。
我们引入一个第三方库(library level),当我们想修改Block的展示方式时,
并不需要修改第三方库中的源码,而是新建一个更具体的层次,
写一些附加的CSS规则在工程层(project level)上覆盖上层的实现即可。
层次概念不仅可以体现在代码的逻辑结构上,还能体现在文件组织方式上。
library.blocks/
button/
button.css # CSS implementation in the linked library (height 20px)
project.blocks/
button/
button.css # Redefinition of CSS implementation (height 24px)
3. 命名规范
随意命名会打破Block,Element与Modifier之间的层次关系。
因此,我们需要增加分隔符来表示BEM结构。
下面我们以表现层的CSS为例,来进行说明。
(1)Block name
Block的名字代表了Block中的Element和Modifier的有效范围。
例如:menu
<div class="menu">...</div>
(2)Element name
Element名字与Block名字用双下划线分隔__
。
例如:menu__item
<div class="menu">
...
<span class="menu__item"></span>
</div>
(3)Modifier name
Modifier的名字与所属的Block或Element用单下划线分隔_
。
例如:menu_hidden
<div class="menu menu_hidden">...</div>
<div class="menu">
...
<span class="menu__item menu__item_visible menu__item_type_radio"></span>
</div>
注:menu__item_type_radio
,Modifer的值与名字也用单下划线分隔_
。
此外还有几种其他命名规范可供选择:
Harry Roberts' style,CamelCase style,
"Sans underscore" style,No namespace style
4. JavaScript for BEM
在JavaScript中,Modifier用来表示一个Block或Element的行为逻辑,即它们的状态。
BEM使得JavaScript操作的对象不再是CSS class而是Block,Element或者Modifier。
document.querySelector('.button').addEventListener('click', function() {
document.querySelector('.popup').classList.toggle('popup_visible');
}, false);
以上代码可以改写为:
block('button').click(function() {
block('popup').toggleMod('visible');
});
Modifier可以看做Block的状态,实现了Block的行为逻辑。
通过增删Modifier,Block可以完成状态间的跳转。
i-bem.js是遵循BEM方法论的一个JavaScript框架。
(1)它使得我们可以用Block,Element以及Modifier来开发软件。
(2)它用声明状态的方式来描述Block的逻辑。
(3)非常方便的与BEM风格的模板或CSS集成。
(4)Block的实现按层次可以灵活的重新定义(redefine)。
5. File system
BEM,不但影响了我们进行开发的方式,而且,还影响了我们组织文件的方式。
不仅接口文件放在独立的文件中,Block的实现也被放在了不同的文件中。
当文件发送到浏览器中时,会被优化,BEM方式区分了我们看到的代码和发送给浏览器的代码。
BEM的文件组织原则如下:
(1)一个Block的具体实现被划分为不同的组成部分
(2)可选的Element和Modifier被存储在不同的文件中
(3)文件按逻辑含义放在一起,而不是按文件类型
(4)一个工程被划分成多个可被重定义的层级(redefinition level)
例如:
blocks/
input/
_type/ # type modifier directory
input_type_search.css # Implementation of modifier type
# with value search in CSS technology
__box/ # box element directory
input__box.css
input.css
input.js
button/
button.css
button.js
button.png
参考:
BEM - Frontend Development Methodology
Github: awesome-bem