CSS 代码组织和管理规范BEM,OOCSS,SMACSS,ACSS

本文主要讨论的是大型项目中 CSS 代码的组织方式。首先介绍的是前端项目开发方法学 BEM。

BEM

BEM 是一种前端项目开发的方法学,由 Yandex 公司提出。BEM 的名称来源于该方法学的三个组成部分的英文首字母,分别是块(Block)、元素(Element)和修饰符(Modifier)。这三个不同的组成部分称为 BEM 实体。

块即是通常所说的 Web 应用开发中的组件或模块。每个块在逻辑上和功能上都是相互独立的。块中封装了组件相关的 JavaScript、CSS 代码和 HTML 模板。由于块是独立的,可以在应用开发中进行复用,从而降低代码重复并提高开发效率。块可以放置在页面上的任何位置,也可以互相嵌套。同一个块可以在页面上存在多个实例。块的不同实例具有相似的结构。一个典型的块的示例是菜单。一个项目中可以有多个不同的菜单,具体相似的结构和样式。

元素

元素是块中的组成部分。元素不能离开块来使用。BEM 不推荐在元素中嵌套其他元素。在菜单块中,每个菜单项是块中的元素。

修饰符

修饰符用来定义块或元素的外观和行为。同样的块在应用不同的修饰符之后,会有不同的外观。当菜单块出现在页面上的不同位置时,可以有不同的样式。菜单块中的菜单项可以有选中或非选中的状态。
不同 BEM 实体可以互相嵌套,形成 BEM 树。不过 BEM 树和 HTML 页面中的 DOM 树是不同的。BEM 树的抽象层次更高。在实现中需要避免在两者之间建立硬性的对应关系。

CSS 命名规则

具体到 CSS 来说,BEM 的重要内容之一是其引入的 CSS 命名规范。一个良好的命名规范可以帮助开发人员快速的了解 CSS 代码中不同样式规则的含义。这对于团队协作和代码维护有很大好处。BEM 有自己独特的 CSS 命名规则,与 BEM 中的三种实体相对应。

目前来说,比较流行的是由 Harry Roberts 提出的命名规范,也是 Google 的 Material Design Lite 库使用的命名规则。本文中的代码也使用该规则。该命名规则的原则如下:

  • BEM 实体名称全部是小写字母或数字。名称中的不同单词用单个连字符(-)分隔。
  • BEM 元素名称和块名称之间通过两个下划线(__)分隔。
  • 布尔修饰符和其所修饰的实体名称之间通过两个连字符(–)来分隔。不使用名值对修饰符。

通过使用上面 CSS 命名规则,所得到的是一系列只使用单个 CSS 类别选择器的样式规则。以菜单组件作为示例来说明。示例中包含了 BEM 块 menu、元素 item 和修饰符 selected。

<ul class="menu">
<li class="menu__item menu__item--selected">Menu Item 1li>
<li class="menu__item">Menu Item 2li>
<li class="menu__item">Menu Item 3li>
ul>
.menu {
 list-style: none;
}
.menu__item {
 font-weight: bold;
}
.menu__item--selected {
 color: red;
}

传统的命名规则:

<ul class="menu">
<li class="item selected">Menu Item 1li>
<li class="item">Menu Item 2li>
<li class="item">Menu Item 3li>
ul>
.menu {
 list-style: none;
}

.menu .item {
 font-weight: bold;
}

.menu .item.selected {
 color: red;
}

比较这两种不同的方式,
BEM 的优点在于所产生的 CSS 类名都只使用一个类别选择器,可以避免传统做法中由于多个类别选择器嵌套带来的复杂的属性级联问题。在 BEM 命名规则中,所有的 CSS 样式规则都只用一个类别选择器。因此所有样式规则的特异性(specificity)都是相同的,也就不存在复杂的优先级问题。这可以简化属性值的层叠规则。可能的缺点在于 CSS 类名会比较长而且复杂。
传统命名方式的优点在于每个 CSS 类名都很简单明了,而且类名的层次关系可以与 DOM 节点的树型结构相对应。

OOCSS

OOCSS 表示的是面向对象 CSS(Object Oriented CSS),是一种把面向对象方法学应用到 CSS 代码组织和管理中的实践。面向对象方法学中的很多理念,如模块化、单一功能原则(Single responsibility principle)和关注点分离(Separation of concerns)等,对于需要组织和管理大量 CSS 代码的应用也是适用的。OOCSS 提出了 CSS 对象的概念,用来表示重复出现的可视化模式。这些模式可以被抽象成独立的 HTML、CSS 和 JavaScript 代码片段,并在整个项目中共享。

OOCSS 有两个重要的原则:

第一个原则是把结构和外观分开。重复出现的可视化模式应该只关注外观,而与 DOM 结构无关。这就要求 CSS 对象中的每个组成部分都有名称,并在 DOM 结构中通过 CSS 类名与之对应。因此在 OOCSS 中的样式规则都是使用类别选择器,而不依赖特定的 DOM 结构。这样可以提高 CSS 对象的可复用性。

第二个原则是把容器和内容分开。这就要求在 CSS 样式中不应该出现与 DOM 树中的位置相关的规则。CSS 样式应该只关注内容,而不是 DOM 元素及其层次关系。

OOCSS 除了这一套指导理论之外,还提供了一些 CSS 对象作为示例。比如多媒体对象,用来描述图片视频及其相关的文字。多媒体对象在 Facebook、Twitter 和微博上会经常出现。每条微博的左侧是用户的头像,右侧是文本内容。多媒体 CSS 对象中的 CSS 类有 media、img、bd 和 imgExt。这几个 CSS 类的含义如下:

  • media - 最外层的 CSS 类,用来表明这是一个多媒体对象。
  • img - 表示出现在左侧的链接、图片或视频对象。
  • bd - 表现出现在右侧的主要内容。
  • imgExt - 表示额外的链接、图片或视频对象,出现在 bd 表示的主要内容的右侧。
    多媒体 CSS 对象代码片段:
<div class="media">
<a href="http://oocss.org/" class="img">
<img src="https://placehold.it/50x50"/>
a>
<div class="bd">
OOCSS media object
div>
div>这里写代码片
.media {
 margin: 10px;
}

.media, .bd {
 overflow: hidden;
}

.media .img {
 float: left;
 margin-right: 10px;
}

.media .img img {
 display: block;
}

.media .imgExt {
 float: right;
 margin-left: 10px;
}

SMACSS

SMACSS 表示的是可扩展和模块化 CSS(Scalable and Modular Architecture for CSS)。Jonathan Snook 在其同名的书中提出了这一思想。SMACSS 的基本理念是可扩展和模块化,并给出了在大型项目中管理和组织 CSS 文件的一些原则。SMACSS 把 CSS 样式规则分成若干个不同的类别:

  • 基础:该类别中包含的是默认的 CSS 样式。作为其他样式的基础。
  • 布局:该类别中包含与页面布局相关的 CSS 样式,用来进行模块的排列。
  • 模块:该类别中包含的是可复用的模块的 CSS 样式。
  • 状态:该类别中的 CSS 样式用来描述布局和模块在不同状态下的外观。比如在不同的屏幕尺寸下,布局会发生变化。标签式模块的每个标签页可以有显示或隐藏的状态。
  • 主题:该类别和状态类似,只不过是用来改变布局和模块的视觉效果。

对于不同类别的 CSS 样式,SMACSS 有不同的命名规则。基础类别中样式一般使用元素类型选择器,用来规范元素的初始样式。布局类别中的样式一般使用“l-”作为前缀。状态类别中的样式一般使用“is-”作为前缀。而对于不同的模块,则使用模块的名称作为前缀。

ACSS

ACSS 表示的是原子化 CSS(Atomic CSS),是 Yahoo 提出来的一种独特的 CSS 代码组织方式,应用在 Yahoo 首页和其他产品中。ACSS 的独特性在于它的理念与一般开发人员的理解有很大的不同,并挑战了传统意义上编写 CSS 的最佳实践,也就是关注点分离原则。ACSS 认为关注点分离原则会导致冗余、繁琐和难以维护的 CSS 代码。

ACSS 的原则是把 CSS 样式打散成尽可能小的部分,每个 CSS 类只对应一条样式规则,从而达到最大化的可复用性。比如 CSS 类 M(10px)所对应的样式规则是 margin: 10px。在应用 CSS 样式时,只需要在把所需要的原子化 CSS 类名添加到 DOM 元素上即可。ACSS 提供了 Atomizer 工具来生成最终的 CSS 样式文件。

在 HTML 页面中,按照 ACSS 的命名方式添加所需要的原子化 CSS 类名,再使用 Atomizer 工具来解析 HTML 页面并生成对应的 CSS 文件。使用 ACSS 的多媒体对象示例:

<div class="BfcHack M(10px)">
<a href="http://oocss.org/" class="Fl(start) Mend(10px)">
<img src="https://placehold.it/50x50"/>
a>
<div class="BfcHack">
OOCSS media object
div>
div>
.Fl\(start\) {
 float: left;
}
.M\(10px\) {
 margin: 10px;
}
.Mend\(10px\) {
 margin-right: 10px;
}
.BfcHack {
 display: table-cell;
 width: 1600px;
 *width: auto;
 zoom: 1;
}

ACSS 的好处在于所生成的 CSS 文件只包含必须的内容,而且冗余很少,可以减少 CSS 文件的尺寸,提高性能。另外 CSS 类所对应的样式规则是不变的,这使得在不同的项目和组件之间共享 CSS 变得很容易。比如在使用传统的方式时,同样是名称为 header 的 CSS 类,其所实际表示的样式规则在不同的项目中可能完全不同。而在 ACSS 里面,名称为 M(10px)的 CSS 类所表示的样式规则永远都是 margin: 10px。ACSS 可能的缺点在于它与大多数开发人员所理解的最佳实践差异很大,可能不容易被接受。

CSS 组织和管理

上面介绍了 BEM、OOCSS、SMACSS 和 ACSS 等几种不同的 CSS 命名规则,各有优缺点。对于开发团队来说,最重要的是找到最适合的组织和管理的方式。不需要盲目的遵循所谓的最佳实践,而是要找到最适合的方式。笔者根据个人经验推荐下面的组织和管理方式。

ACSS 的思想虽然有很多的优点,也在 Yahoo 这样的大公司得到了生产实践,但是 ACSS 的做法可能比较难以被大多数开发人员所理解,因此除非是团队的决策,否则不推荐使用。比较推荐的做法还是模块化,更容易让人所理解。

首先需要一个基准的 CSS 样式表。这可以使用 Normalize.css 和 Bootstrap 4 中的 Reboot。然后是进行模块划分。对每个模块中采用 BEM 来作为命名规则。在现在的 Web 项目中,一般不直接编写 CSS,而是使用 SASS 或 LESS 这样的 CSS 预处理语言来编写。

小结

现在的 Web 应用中 CSS 代码的数量越来越大,开发团队的规模也相应扩大。在 CSS 开发团队中需要一个统一和固定的 CSS 代码组织和管理规范。这其中也包括 CSS 样式的命名规则。BEM、OOCSS、SMACSS 和 ACSS 都是很不错的 CSS 代码组织和管理的指导实践。开发团队可以根据成员的意愿选择最合适的方式。
原文链接:从 BEM 谈大型项目中 CSS 的组织和管理

你可能感兴趣的:(css)