面向对象的CSS(OOCSS)

特别声明:此篇文章由D姐根据Louis Lazaris的英文文章原名《An Introduction To Object Oriented CSS (OOCSS)》进行翻译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://coding.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss以及作者相关信息

你曾经听过这样一句话:“内容就是王道”吗?作为一位Web开发者,因为工作的缘故经常与内容打交道,这可能是很正常不过了。对于我们已经是过渡使用,但是什么才能把游客吸引到一个网站才是真正的一道。

从一个Web开发者的观点来看,一些人认为速度才是王道。久而久之,我也开始认同这个观点。近年来许多有经验的前端工程题提供建议”如何才能通过一些最佳实践的方法提高用户体验度呢?”

不幸的是,众多开发者忽视了CSS的表现(认为他太过简单,是一种机械的工作),而把更多关注在Javascript的性能上或者其他方面。

在这篇文章中,我将通过面向对象的css概念的介绍,让你了解一些经常被忽视的地方是如何在改善用户体验和网页可维护性上面发挥作用的。

OOCSS面向对象的css原则

任何基于面向对象的代码方法,其主要目的都是鼓励代码的复用。OOCSS也是一样,讲究复用,并最终可以更快更高效的书写你的样式,同时方便日后的添加和维护。

根据oocss在github上的描述,oocss是基于两个主要原则

1、结构与样式的分离

几乎页面上的每个元素都有不同的视觉特效(也叫皮肤),他们在不同的环境中重复的在使用。思考一下,一个网站的品牌logo,它的颜色,细微的渐变或是可见的边框。另一方不是视觉特效(结构)也在不断的重复使用。

当把这些不同的特性抽象到一个基于类的模块里,他们变得可复用,可以运用到任何的元素上,并且具有相同的效果。让我们来看一个代码的前后对比,你就明白我在说些什么了。

在运用oocss的原则前,你的css可能是这个样子的:

#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选择器定义的样式。但是他们也有一些公用的样式。这些公用的样式由网站品牌风格或设计风格所决定的。

由于一些长远考虑,我们抽象出一些公用的样式所以结果成这样:

.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”类名添加给所有的元素,除了更少的使用了利用代码之外,其效果和前面的例子前生的效果一模一样。

2、容器与内容的分离

关于oocss在github上的描述,第二个原则是容器与内容的分离。为了说明这个的重要性,采用以下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;
}

这些样式将运用到ID为“#sidebar”的子元素“h3”上,但是如果想把字体大小和文本阴影之外的样式运用到脚部具有相同效果的“h3”上,又应该怎么办?

然后我们也许需要这样做:

#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;
}

这样写代码的,或许初学人员会经常犯的,就算是你从事过前端工作一段时间,有一定的经验了,或许还是会犯这样的错误。犯错误是好事,但是犯了这样的错误你是否有思考过,为什么会写成这样?如果你从没有思考过,只是照旧这样写,那就是糟糕的一件事了。因为你只是在机械的工作,为了完成boss给你的任务而且。长期下来是件恐怖的事情。

今天我们没有复用样式可能觉得不必要,也许没有意识到(或是简单的根本不关心)。随着OOCSS的推行,我们鼓励大家长远考虑一下不同元素的公用样式是什么?然后把他们分离成模块或是对象,以便可以重复用到任何需要的地方。

在上面的例子中,用后代选择器声明的样式是不能复用的,因为他们依赖于一个特定的容器(在这里例子里要么是侧栏要么是页脚)。

当我们用基于oocss建立的类模块,我们确保我们的样式不依赖于任何包含元素。这意味着他们可以在文档的任何地方被复用,无论结构如何。

3、现实生活中的一个例子

为了进一步说明oocss是如何运用的,在我的网站最新设计我将做一些类似的工作。在我编写完我的网站页头的inner元素后,我意识到这个头部内部的一些基础结构也许可以复用到页面的其他元素上。

如下是我沿用以前的写法开始写的页头样式

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

列在这里的一些样式是类名为“header-inner”元素的独特样式。但是其余可以复用的样式我都把他们组成一个模块。这样我就可以抽出结构,样式添加到我们自己的复用类里,如:

.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居中
为子元素创建一个定位的参照物
左右内留白padding为20px
为清除浮动设置overflow:hidden

现在我们可以自由的把这些样式运用到需要相同特征的任何元素,只需给需要的元素添加类名的简单方式,而无需写一行额外的css代码。

对于我的网站,我在主要的内容元素和页脚内部元素复用了这些结构样式。根据设计,这些样式也许可以运用到水平导航元素,可能会出现在标题和内容,或是任何有固定宽需要在页面居中的其他元素。

给这些元素添加“globalwidth”样式后,结构可能是这样的:

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

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

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

也许有人会觉得这种抽象html结构样式的方式,有悖于结构与表现分离的原则

媒体对象

Nicole Sullivan是OOCSS先驱者之一,她创建了一个可以复用的模块称为媒体对象,正如她解释道,可以节省数百行的代码

媒体对象是体现oocss能力的很好的例子,因为它里面容许包含任何尺寸的媒体元素的内容。尽管许多在他内部运用样式的内容甚至是媒体元素大小本身可能改变,但是媒体对象本身具有的通用基本样式有助于避免不必要的重复。

OOCSS的好处

我已经提到了一些oocss的好处。这里我将对他们做些扩展

1、更快的网站

Oocss带来的好处是很明显的。如果在你的css中有较少的重复样式,那么将使得文件体积更小,从而更快的下载这些资源。

的确,标记将更加混乱,从而创建更大的HTML文件。但是许多情况下标记结构损失很多,却换来了样式表现性能大大提升的效果。

另一个需要记住的概念是在oocss的wiki里面提到他的附属品。这指的是每次在你的css中复用一些样式,本质上就会创建一个有着0行样式的元素。对于大型,高流量的项目,这些附属品有可能是影响性能表现的关键因素。

2、可维护的样式表

随着oocss取代不断增长的特殊样式表,你将有一个易于维护的模块,在里面层叠发挥了重要的作用。

当在现有网站上添加新页面,你将不会不考虑前面的代码,直接在样式表最后添加新的样式。相反你将会复用现有的样式,并在现有样式的基础上扩展你需要的样式。

随着这种类型的长远设想,有可能创建一整个页面只有很少的css代码。任何css模块可以作为所有新页面的基础,这样新css页面就会很小。在某种情况下甚至可以创建一个全新样式的页面却没有一行css代码。

这些可维护性的好处也增强了你的样式表的健壮性。因为样式表已经模块化了,页面是基于oocss搭建的,所以即使一个新开发人员开始使用样式表也不太会破坏它。

需要注意的问题

在社区中对oocss的建立有很大的讨论,并引起了一些争议。这里我想尝试消除一些常见的误解

1、你仍可以使用id

如果你决定用oocss作为你工作的唯一方式,然后你的样式将大量基于css类名建立,你将不会使用id选择器给元素创建样式。

正因为如此,许多人错误声称oocss鼓励完全放弃id的使用。但这是不对的。

避免使用id的规则更具体的说,不在选择器中使用id。所以这是oocss使用原则完全接受的(避免样式使用id选择器),因为你html中的id是用于javascript的钩子和片段标识。

当然,你可能有这样一种情况:你已经把一个id运用到一个元素,而这个元素你知道他在页面中是唯一的。所以,你避免在元素上添加类名节省了几个字节,而是给他使用了id选择器。但是即使在这样一个例子中,依赖于一个类名是更安全的,因为他确保未来你不会遇到特殊的问题。

2、处理较小的项目

对于较小的网站和应用程序,你也许认定oocss在这种情况下是大材小用了。所以这篇文章中倡导的oocss并不适用于所有的项目,他将取决于这个项目本身。

尽管如此,我认为这是个好主意,至少在你所有的项目中开始考虑oocss的运用。一旦你掌握了他的诀窍,我肯定你会很容易发现,他致力于越大的项目收到oocss带来的好处就越明显。

一些实用指导

开始应用oocss是可能需要一些时间的,我现在仍在使用它,所以我不敢声称我知道这一领域的所有答案和经验。

但是这里有些注意事项可能帮助你用oocss的思维方式开始使用oocss:

避免后代选择器(如不要使用类似于.sidebar h3)
避免用id作为样式钩子
避免在你的样式表中给类名附属一个元素名(如不要这样做div.header or h1.title)
除非一些很少的情况,避免使用!important
使用CSS Lint检查你的css(这样你可以知道他有哪些选项和疯狂的方法
使用CSS网格

支付宝扫码打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者