多读书,多运动,多到远处走走,再看看不一样的世界。
当我们构建一个小的web应用的时候,怎样合理的组织页面样式并不是一个大的问题,而一但web应用体量逐渐增大的时候,就需要一定的规范和技巧来减少大的应用开发过程中front-end developers
和back-end developers
的联调消耗,应对这种场景由此产生了SMACSS[1]、OOCSS[2]以及BEM[3]等技术。
BEM Methodology will massively improve code maintainability and speed up the development process[4].
BEM
是Block
、Element
和Modifier
的缩写,其思想是通过模块化命名dom元素进行css样式的管理,以增强css和类名的可读性和易用性(所以这种命名方式只能用于classes而不能用于IDs)。
这里的Block
是抽象的产物,按照Josh Medeski的说法:‘The block is the container or context where the element finds itself. [5]’,BEM解释在整体web应用中任何一个模块都是一个对象,即Block
(模块对象),每一个模块一一对应相应的css样式,比如一个简洁的百度页面:
将它的每一部分都进行边框线划分:
此时按照BEM的思想,每一个边框内的元素都是一个Block
对象,彼此之间相互独立又存在相互嵌套。假设其中的某个div
存在.content
类名,中间嵌套input
。
<div class="content">
<input type="text" class="search">
</div>
其css样式:
.content {/* Styles */}
.search {/* Styles */}
看上去和我们平常组织的css样式写法并无区别,其中差异更多的是思想上的不同,也就是为下面Element
和Modifier
概念的引申进行铺垫。
这里我们期望Element
代表一个功能性的事件元素,比如:
<div class="content__section">
<input type="text" class="search__input">
</div>
其css样式:
.content__section {/* Styles */}
.search__input {/* Styles */}
Modifier
用于修饰,
<div class="content__section--featured">
<input type="text" class="search__input--icon">
</div>
其css样式:
.content__section--featured {/* Styles */}
.search__input--icon {/* Styles */}
Block
命名通常应用常见的.content
、.header
、.footer
、.sidebar
、.area
等,有时可能我们期望Block
的命名能够更长且详尽一些,如.content
变为.content-box
,即约定可以用-
来延长Block
。
.content-box {/* Styles */}
Block
与Element
之间连接用__
,或者说每一个Element
都是由__
开始的。
.content__section {/* Styles */}
Block
与Modifier
之间连接用--
,如section--featured
。另一个约定的规范是用_
进行连接,如section_featured
。
.section--featured {/* Styles */}
通常我们在一个div的.header
标签里可能添加了需要修饰的.header--fix
,但是不是所有的.header
功能性类模块都要进行.header--fix
处理,所以最好如下:
<div class="header header--fix">
<!-- html -->
</div>
BEM的命名替换方案有Harry Roberts style和CamelCase style
Harry Roberts style示例:
.block-name__element-name--modifier-name {/* Styles */}
约定规范的原文如下:
- Names are written in lowercase
- Words within the names of BEM entities are separated by a hyphen -
- An element name is separated from a block name by a double underscore __
- Boolean modifiers are delimited by double hyphens --
- Key-value type modifiers are not used
CamelCase style示例:
.BlockName__ElementName_ModifierName {/* Styles */}
在我所阅读的《How to Use BEM Methodology》
一文中有张图片形象的展示了如何应用BEM
技术构建合理规范的UI,并列举了XML
→JSON
→HTML
之间的对应关系。
XML:
<block:header>
<block:logo/>
<block:search-from>
<block:input/>
<block:button/>
</block>
<block:lang-switcher/>
</block>
JSON:
{
block: 'header',
content: [
{ block: 'logo' },
{
block: 'search-form',
content: [
{ block: 'input' },
{ block: 'button' }
]
},
{ block: 'lang-switcher' }
]
}
HTML:
<header class=”header”>
<img class=”header__logo”>
<form class=”header__search-from”>
<input class=”header__search-from__input” type=”input”>
<button class=”header__search-from__button” type=”button”>
</form>
<div class=”header__lang-switcher”></div>
</header>
从图中我们可以看出BEM更倾向于模块对象(Block)
和语义化
,但这里其实也是有争议的,比如Thierry Koblentz
就提出:'If you check the W3C's "Tips for Webmasters" ,where it says "Good names don't change," you'll see that the argument is about maintenance, not semantics per se[6]'的论证观点用于阐述HTML标签的类名不应该过分强调语义化。
TOMISLAV MATIJEVIĆ
对于BEM有一个形象的比喻,他将一个Block
看作是一个人(person)。
人具有身体部位和不同性别,这里假定描述一个女生(female)的手部(hand)、腿部(leg)和左手(hand-left)。
用SASS描述CSS:
.person {
&__hand {/* Styles */}
&__leg {/* Styles */}
&--female {
/* Styles */
&__hand {
/* Styles */
&--left {/* Styles */}
}
&__leg {/* Styles */}
}
}
如果想更快速的书写样式,TOMISLAV MATIJEVIĆ
集成了SASS书写BEM的方法:
// Block Element
// @param {String} $element - Element's name
@mixin element($element) {
&__#{$element} {
@content;
}
}
// Block Modifier
// @param {String} $modifier - Modifier's name
@mixin modifier($modifier) {
&--#{$modifier} {
@content;
}
}
.person {
@include element('hand') {/* Person hand */}
@include element('leg') {/* Person leg */}
@include modifier('female') {
/* Person female */
@include element('hand') {
/* Person female hand */
@include modifier('left') {
/* Person female left hand */
}
}
}
}
输出效果:
.person__hand {/* Person hand */}
.person__leg {/* Person leg */}
.person--female {/* Person female */}
.person--female__hand {/* Person female hand */}
.person--female__hand--left {/* Person female left hand */}
构建需要使用ENB,具体方法官网上也有详尽描述:Starting your own BEM project。
Normalize.css[7] | CSS Tools[8] | aliceui[10] |
具体的css reset选择可以阅读John W. Long的Modular CSS typography[9],也许可以提供一些灵感。