liuqipeng

面向对象的 CSS (OOCSS)

liuqipeng · 2016-12-07翻译 · 963阅读 原文链接

你是否听说过一个词语叫“内容就是王道”?作为一个 Web 开发者,我们的工作与内容创作有着频繁的联系。这是一条经常被引用,并且正确地解释了什么因素吸引了人们访问网页的谚语。

然而,从 Web 开发者的角度来看,一些人认为速度就是王道。近年来,许多有经验的前端工程师已经提出了如何通过最佳实践来改善用户体验的建议。逐渐地,我也开始赞同这个观点。

不幸地是,当许多开发者们(为了更好的原因)将关注点大量地聚焦于 JavaScript 的性能和其他领域时,CSS 看起来有所被忽略。

在这篇文章里,我会在这个被忽略的领域引入一个新的概念——面向对象的 CSS ,并且阐述它是如何改善你的 Web 页面性能和可维护性的。

OOCSS 的原则

与任何基于对象的编程方法一样,OOCSS 的目的是鼓励代码复用,使得最终的样式可以更快地和更有效地添加和维护

OOCSS

正如 OOCSS GitHub repo’s Wiki page 所描述,OOCSS 有两个主要的原则。

从皮肤分割出结构

在一个有样式的 Web 页面里,几乎每一个元素都有着不同的可见视觉特征(例如“皮肤”),这些特征会重复出现在不同的上下文。想一下一个网站的品牌——颜色,gradients的妙用,又或者可视的边框。另一方面,其他通常的不可见特征(例如“结构”)同样是重复出现的。

当这些不同的特征被抽象到基于类的模块里,它们变得可以被复用并且可以被应用到任何元素,使得元素有着相同的基础效果。通过对比前后代码,你就会知道我在讨论什么了。

在使用 OOCSS 原则之前,你也许已经有了类似代码,如下:

#button {
  width: 200px;
  height: 50px;
  padding: 10px;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

#box {
  width: 400px;
  overflow: hidden;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

#widget {
  width: 500px;
  min-height: 200px;
  overflow: auto;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

上面的三个元素都有各自独特的样式,并且它们被应用于不可重用的 ID 选择器来定义样式。但是它们有着大量通用的样式。那些通用的样式也许为了品牌的目的或者设计的一致性。

我们加上一点点计划和考虑,可以把通用样式抽象出来,使得 CSS 最后变成以下这个样子:

.button {
  width: 200px;
  height: 50px;
}

.box {
  width: 400px;
  overflow: hidden;
}

.widget {
  width: 500px;
  min-height: 200px;
  overflow: auto;
}

.skin {
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

现在所有的元素都使用类来定义,通用的样式被结合到一个可复用的 “skin” 类里,这里面没有东西是不必要的、重复的。我们仅仅需要把 “skin” 类应用到所有的元素,就会得到与第一个例子产生的效果一致,在这里我们先不考虑更少的代码以及进一步复用的可能性

容器和内容的分割

在 OOCSS GitHub wiki 页面上所描述的第二个原则是从内容里分割出容器。为了证明这个原则为什么这么重要,思考以下的 CSS 代码:

#sidebar h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: .8em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

这样样式将会应用在所有 #sidebar 元素下的 h3 子元素。但是,假如我们希望将除了字体大小和文本阴影外的相同样式应用在 footer 呢?

接下来我们需要做类似事情,如下:

#sidebar h3, #footer h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 2em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

#footer h3 {
  font-size: 1.5em;
  text-shadow: rgba(0, 0, 0, .3) 2px 2px 4px;
}

或许我们最后做的比上面更糟糕:

#sidebar h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 2em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

/* other styles here.... */

#footer h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 1.5em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 2px 2px 4px;
}

现在我们使得许多样式没有必要地重复,并且根本没有意识到这个问题(或者简单来说是我们不在意)。OOCSS 鼓励我们更多地去思考:在这些不同的元素里有什么是通用的,并且将这些通用的特征分割到模块或者对象里去,使得它们可以被任何地方复用。

在上面的例子里,那些被声明使用了子孙选择器的样式是不可复用的,因为它们依赖于一个特殊的容器(在这个例子里就是 sidebar 或者 footer)。

当我们使用 OOCSS 原则下的基于类的模块建设方法,我们需要确保样式是不依赖于任何容器元素的。这意味着它们可以不需要理会任何结构上下文,可以在 document 里的任何地方复用。

一个真实案例

为了进一步说明 OOCSS 是如何被使用的,我会使用相似的做法来改善我所做的 my site’s recent redesign 页面。在编写完页面里的内部 header 元素后,我意识到 header 里面的基础结构样式是可以被页面里的其他元素所复用的。

以下几行是我一开始为我的 header 所写的样式:

.header-inside {
  width: 980px;
  height: 260px;
  padding: 20px;
  margin: 0 auto;
  position: relative;
  overflow: hidden;
}

在这里的列举一些样式对于 .header-inside 元素来说是唯一的。但是剩下的部分可以组成一个复用的模块。因此我可以抽象出结构样式到可复用的类里。以下是抽象后的结果:

.globalwidth {
  width: 980px;
  margin: 0 auto;
  position: relative;
  padding-left: 20px;
  padding-right: 20px;
  overflow: hidden;
}

.header-inside {
  padding-top: 20px;
  padding-bottom: 20px;
  height: 260px;
}

属于 .globalwidth 类的样式应该遵循以下:

  • 一个固定的宽度

  • 居中使用 margin: auto

  • 为了子元素使用相对定位来创建一个位置上下文

  • 左右内间距为 20px

  • 为了 clearfixing 将 overflow 设置为 “hidden”

现在我们无需写多一行额外的 CSS 代码,就可以非常自由地使用这些样式,只需要简单地通过增加一个类给那些希望有着相同特征的节点即可。

在我的站点里,我复用了这些结构样式在主要的内容元素以及内部 footer 元素上。根据设计,这些样式也可以被应用于出现在页头和内容之间的水平导航元素,又或者任何一个有着固定宽度以及需要在页面中居中的元素。

在给这些元素增加 “globalwidth” 样式后,标记语言就会像以下这样:

<header>
  <div class="header-inside globalwidth">
  </div>
</header>

<div class="main globalwidth">
</div>

<footer>
  <div class="footer-inside globalwidth">
  </div>
</footer>

有些人会觉得这种样式抽象使得标记变得杂乱,违反了将标记从表现分割的原则。

但是撇开关于这会如何影响标记的争论,没有人可以质疑的是,抽象结构化这三个元素令页面更容易跟踪和修改常用的样式

媒体对象

OOCSS 的先驱之一是 Nicole Sullivan。她创建了一个名为 media object 的项目,她认为这个项目可以节省数百行代码

OOCSS

媒体对象是一个展示 OOCSS 能力很好的例子,因为它可以在它的右边包含任何大小的媒体元素作为内容。尽管许多样式被应用到媒体对象里面的内容,甚至媒体对象自身大小是可以变化的,但是媒体对象自身通用基础样式可以帮助它避免不必要的重复。

OOCSS 的优点

我已经提取了一些 OOCSS 的优点。接下来我会对此展开说明。

更快的网站

OOCSS 带来的性能优势是清晰可见的。如果在你的 CSS 代码里有更少的样式,这就会使得文件尺寸变小,从而更快地下载资源。

当然,这同样会使得 HTML 文件变得杂乱并且尺寸变大。但是从许多案例里来看,从样式表获取到的性能将会大大弥补标记丢失的性能。

另外一个我们需要记住的概念就是 OOCSS wiki 里提及的“性能赠品”。这是指每次你在 CSS 里复用某些样式,你就无需使用 CSS 代码创建新的样式元素。对于大型、高流量的项目,这些“免费赠品”将成为关键的性能收获

可维护的样式表

在自然层叠样式作为一个重要角色的项目里,使用 OOCSS 使得你无需为样式表的不断增长而进行一场特殊的战斗,它只会让你有一系列易于维护的模块。

当为现有的站点添加样式,在使用 OOCSS 前,你需要考虑在这之前添加到样式表里的代码,然后把新的样式添加到样式表的底部。使用 OOCSS 后,你只需要复用现有的样式以及根据现有的规则集进行扩展样式即可。

在这种思考方式下,有可能使得创建整个页面只需要编写极少的 CSS 代码。任何已经存在的 CSS 模块都可以作为基础服务于所有新页面,并且新的 CSS 代码将会极小。在某些案例里,你甚至可以无需编写一行代码就可以创建一个充满样式的页面。

这些可维护的优势也会延续到样式表的健壮性。因为样式是模块化的,页面是基于 OOCSS 构建的,所以当一个新来的开发者开始用使用这些样式表是不太可能去破坏到这些东西的。

值得注意的点

OOCSS 已经在社区里创建了大量讨论,并且引发了一些争论。在这里,我会尝试消除一些常见的误解。

你仍然可以使用 IDs

如果你决定单独使用 OOCSS 的方式进行工作,你的样式会大量地基于 CSS 类,并且你不能使用 ID 选择器给元素加样式。

正因为此,许多人谎称 OOCSS 鼓励人们完全抛弃 IDs 的使用,但这是不正确的。

避免 IDs 的使用,更具体地讲是避免使用 IDs 在样式表的选择器里。你还需要用 IDs 在你的 HTML 里作为 JavaScript 的钩子和代码片段的标识符,因此在 OOCSS 原则里这是完全可以接受的。

当然,有一种情况就是你已经将一个 ID 应用在一个元素上,并且你知道在页面里这是唯一的。因此你可以通过用 ID 选择器来捆绑样式,避免给这个元素增加一个类,从而节省一些字节。但是即使在这个例子里,依靠一个类去实现可以确保未来不会出现特别的问题。

处理较小的项目

对于小型站点和应用,可以肯定的是 OOCSS 会矫枉过正。因此不要在任何环境下都把这篇文章作为 OOCSS 的宣传,OOCSS 同样依赖于不同的项目。

尽管如此,至少在你的项目里思考 OOCSS 是一个好主意。一旦你掌握了它,我相信在更大的项目里它会更加容易使用,带来的优势也会更加显著和确切。

实践的一些指引

开始使用 OOCSS 是需要时间的。我还在研究和探索它,我不会声称在这个领域我已经有了所有的答案和经验。

但是这里有一些你想要的经验,它们会帮助你进入 OOCSS 的思维模式:

  • 避免使用子孙选择器(例如:不要用 .sidebar h3

  • 避免使用 IDs 作为样式钩子

  • 避免将类依赖于元素 (例如:不要用 div.header or h1.title)

  • 除了在少数例子里,避免使用 !important

  • 使用 CSS Lint 检查 CSS 代码 (你需要知道它有选项以及疯狂的方法)

  • 使用 CSS grids

显而易见,在一些时候这些规则是会被打破的,但是总的来说,这些是好的开发习惯,会使得样式表更小以及更容易去维护。

跟随 Nicole Sullivan 的工作

如果你想继续学习 OOCSS,在行业里最需要跟随的人就是 Nicole Sullivan

Nicole 除了在她的博客里定时发布文章,还会用幻灯片做大量的展示。以下是一些你想知道的:

结论

许多人害怕 OOCSS 的思想是因为这看起来违反了许多我们所学习的“最佳实践”,但是一旦长期使用 OOCSS 带来的有益之处被大家所认识,我确信许多开发者将会转变他们的思想。

整体来看,我认为 OOCSS 在 CSS 的发展路程中会有一个明亮的未来,它是一个所有开发者都应该结合到项目中的思想——至少,在某个方面,这样将会使得 Web 页面更加的快速、高效,以及更加容易维护。

相关文章