BEM和CSS方法论
CSS是一种“奇怪”的编程语言,用来描述网页的样式。使用起来很简单,却由于自身的缺陷(只有全局作用域、没有模块化)使得它很难像真正的编程语言那样,有软件工程的办法适用。
BEM
BEM是一个方法论,是一套使用CSS的惯例和约定,用于写出更具有维护性和重用性的CSS代码。BEM由Yandex公司提出,目前已被广泛采用。它和其他的CSS的规范如OOCSS,SMACSS并不冲突。它们都用来提高CSS文件的可维护性。
规范
BEM的三个字母分别代表块(block)、元素(element)、修饰符(modifier)。根据官网的介绍:
Block
代表一个独立的抽象的组件Element
代表依附于Block
的后代,用来形成一个完整的block
Modifier
代表Block
或是Element
的不同状态或版本,用来改变默认样式
另外:
- 不要使用文档的层级结构
- 在标签嵌套时,只使用一层嵌套,通过class名标注标签
其中Element
命名时在Block
后添加两个短横线--
,Modifier
在Block
后添加两个下划线__
。所有的CSS均绑定到标签的class上,确保样式的重用性。
1 | .block{} |
之所以采用两个短划线和下划线,是为了让用户自定义的块命名中可以含有单个短划线和下划线。
下面是官网的样例:
1 | <form class="form form--theme-xmas form--simple"> |
1 | .form { } |
怎么用
BEM正如上面介绍的那样,只是一套规范。在使用的时候会感觉类名有些冗长和奇怪。不过它带来的好处是很有价值的。
另外,没有必要在每个地方都使用BEM规范。对于独立的一条CSS样式,写成BEM格式的写法并没有必要。对于考虑使用BEM的人来讲,可能最重要的是从哪里到哪里使用BEM。
OOCSS
写CSS代码很简单,但是写出可维护的CSS代码比其他语言就要更难了。因此,大牛们提出了OOCSS、SMACSS这样的设计模式来让事情更容易。OOCSS(Object Oriented CSS)即面向对象的CSS,它的关键在于创建在页面中创建模块化可重用的对象(HTML和CSS的结合体)。
根据OOCSS之父Nicole Sullivan的说法,OOCSS重点在于:
- 独立文档结构与样式
- 独立文档容器和内容
使用容易理解的话来说,就是从HTML结构上解脱出来,增加CSS class的重复利用。
1 | <nav class="nav--main"> |
上面的例子里,业务代码经常会将CSS选择器写成nav ul li a
这样的写法。这么做过渡依赖原有的HTML文档结构。原有的文档结构改变时,CSS就必须跟着重构。因此,建议直接给a
标签绑定class,或写成nav--main a
的写法。
第二,减少使用id作为CSS的选择器。尽量使用class,类似OOP中的概念,抽出重复的部分,定义在一个class中。像下面这样,定义基本的类button
,并通过button-default
和button-primary
来拓展基本类。
1 | <div class="button button-default"> |
总结一下,OOCSS的优势在于它可以减少CSS的代码减少加载时间(当然的),语义化的类名增强逻辑性和SEO,CSS样式可以轻松拓展,
缺点在于它适合大型网站的开发,在小型项目中似乎用不到这种40米的长刀,同时没有巧妙地使用,创建的组件会适得其反增加,增加维护难度。
SMACSS
SMACSS(读作”smacks”)全称为Scalable and Modular Architecture for CSS。它也是CSS的框架规范之一,目标是让”keep CSS more organized and more structured, leading to code that is easier to build and easier to maintain(作者Jonathan Snook语)“
SMACSS使用了一套5个类别来划分CSS,这种组织和结构规范了CSS写法,提高了CSS使用效率。
- Base rules 类似与
reset.css
和normalize.css
的效果,为文档的标签设置默认样式,应该只包含单独的标签选择器 - Layout rules 将文档分成诸如header,article,footer这样的各个部分,为布局中的每个部分设置样式
- Module rules 页面中可重用部分的样式,在layout中出现多次,使用时避免出现标签选择器
- State rules 用于描述element的不同状态,和基本规则组合使用。
- Theme rules 类似与“皮肤”的概念,更改整个网站的主题。
其他
CSS Modules和上面的思路要来的不大一样。它着眼于解决作用域和模块依赖的问题,采取的做法是重写class名。在React,Vue中每个组件中的CSS样式就做了这样的处理,保证的模块间的CSS文件不相冲突。
在通过JavaScript绑定到特定class的标签上时,也造成了CSS维护的不变。必要的时候可以为HTML标签赋予专为JavaScript使用的类名。如:
1 | <li class="nav--main__item js-nav--main__item"><a>whatever</a></li> |
总结
CSS是一门看起来很简单的语言,但是它的简单性也提升了工程中的使用难度。为了增强它的可用性。许多名为”xxxCSS”的方法论和机制等被发明,类似Sass,SCSS,Compass,Less,stylus,BEM,SMACSS,OOCSS,ACSS,CCSS等。在使用CSS时,可以尝试使用上面的规范,遵守一些法则,以写出更pure的代码。