方法论是一个哲学术语,会对一系列具体的方法进行分析研究、系统总结并最终提出较为一般性的原则。CSS方法论是一种面向CSS、由个人和组织设计、已被诸多项目检验且公认有效的最佳实践。这些方法论都会涉及结构化的命名约定,并且在组织CSS时可提供相应的指南,从而提升代码的性能、可读性以及可维护性。本章会讲解三种CSS方法论:OOCSS、BEM和SMACSS。
一、OOCSS
OOCSS(Object-Oriented CSS)是指面向对象的CSS,由Nicole Sullivan在2009年提出,借鉴了面向对象编程的抽象思维。其核心概念是采用模块化的实现方式,将CSS分解成可复用和继承的对象,也就是将关注点从页面转移到页面内的组件。OOCSS包含两条核心原则,如下所列,每条原则下都给出了相应的示例。
(1)结构与皮肤分离,即不要将位置、尺寸等结构属性和字体、颜色等皮肤属性写在一个选择器中。
<style> .col { float: left; width: 200px; } .line { background: #F60; } style> <div class="line col">div>
(2)内容与容器分离,即让对象的行为可预测,避免对位置的依赖,子元素即使离开了容器也应该能正确显示。
<style> .line { background: #F60; } .unit { width: 50%; } style> <div class="line"> <div class="unit">div> div>
1)命名约定
在OOCSS中,类名既要能传递对象的用途,也要有通用性,例如mod、complex、pop等。如果将CSS类命名的太语义化,例如navigation-bar,那么就会将其限制在导航栏,无法应用到网页的其它位置。
2)缺点
OOCSS的缺点也很明显,如下所列。
(1)虽然样式的粒度变小了,但同时会产生许多充满类的HTML元素。
(2)在避免特殊性冲突时,OOCSS选择的方案是放弃层叠,这样就无法最大程度地利用关系选择器的优势。
(3)为了让类能更通用,在命名时就得弱化语义。
二、BEM
BEM(Block Element Modifier)是指块级元素修饰符,也是在2009年提出,起源于Yandex(俄语版的Google)。BEM分为三部分:
(1)块(Block)是一个独立实体,最高级抽象,相当于OOCSS中的对象,例如菜单、文本框等。
(2)元素(Element)是块的组成部分,被包含在块中,无法自成一体,例如菜单项、标题等。
(3)修饰符(Modifier)是块或元素的状态,可更改它们的外观或行为,例如高亮、选中等。
1)命名约定
BEM中的块、元素和修饰符需要全部小写,名称中的单词用连字符(-)分隔,元素由双下划线(__)分隔,修饰符由双连字符(--)分隔。注意,块和元素都既不能是HTML元素名或ID,也不依赖其它块或元素。
在下面的示例中,.form是块,.form__input和.form__submit是其元素,.form--theme-xmas是其修饰符,而.form__submit--disabled是.form__submit的修饰符。
<style> .form {} .form--theme-xmas {} .form__input {} .form__submit {} .form__submit--disabled {} style> <form class="form form--theme-xmas"> <input class="form__input" type="text" /> <input class="form__submit form__submit--disabled" type="submit" /> form>
BEM的核心思想就是用这种命名约定来清晰的表达出类的含义以及与其它类之间的关系。
2)缺点
BEM的缺点如下所列。
(1)BEM与OOCSS一样,也抛弃了层叠,因此也不能完全挖掘出关系选择器的潜力。
(2)CSS类名可能会比较长而且复杂。
(3)需要完善规则说明文档,否则HTML结构将难以阅读。
三、SMACSS
SMACSS(Scalable and Modular Architecture for CSS)是指可伸缩及模块化的CSS架构,由Jonathan Snook在2011年雅虎工作时提出。他在OOCSS和BEM的基础上添加了五种类别的组件的处理规则,具体如下所列。
(1)基础(Base)是为HTML元素定义默认样式,可以包含属性、伪类等选择器。
(2)布局(Layout)会将页面分为几部分,可作为高级容器包含一个或多个模块,例如左右分栏、栅格系统等。
(3)模块(Module)又名对象或块,是可重用的模块化部分,例如导航栏、产品列表等。
(4)状态(State)描述的是任一模块或布局在特定状态下的外观,例如隐藏、激活等。
(5)主题(Theme)也就是换肤,描述了页面的外观,它可修改前面四个类别的样式,例如链接颜色、布局方式等。
1)命名约定
推荐使用前缀来区分布局、模块、状态和主题,如下所列。
(1)“l-”或“layout-”用作布局的前缀,例如.l-inline、.layout-grid等。
(2)“m-”或模块自身的命名用作其前缀,例如.m-profile、.field等。
(3)“is-”用作状态的前缀,例如.is-collapsed、.is-active等。
(4)“theme-”用作主题的前缀,例如.theme-a-background、.theme-l-grid等。
注意,由于基础规则是直接作用于元素的,因此不需要前缀。
2)共享
在实际工作中,不需要局限于某一个CSS方法论,很多时候可以结合使用,共享模块化CSS的规则。例如遵循OOCSS的第一条分离原则,BEM的命名约定,以及SMACSS的分类前缀,具体如下所列。
(1)基础仍旧沿用SMACSS的规则,布局和模块使用SMACSS的前缀。
(2)子元素用双下划线(__)分隔,其状态前缀沿用“is-”。
(3)修饰符也以“is-”为前缀,与模块组合时用双连字符(--)分隔。
(4)适当层叠,最好保持在一层。
在下面的示例中,.m-notice__img和.m-notice__content是模块的子元素,.is-important是子元素h6的状态,.m-notice--is-active是模块的修饰符。
<style> .l-notice {} .m-notice {} .m-notice--is-active {} .m-notice__img {} .m-notice__content h6 {} .is-important {} style> <div class="m-notice l-notice"> <img class="m-notice__img" /> <div class="m-notice__content"> <h6>......h6> <h6 class="is-important">......h6> div> div>