HTML和CSS的分离

特别声明:此篇文章由Jekst根据的英文文章原名《Decoupling HTML From CSS》进行翻译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://coding.smashingmagazine.com/2012/04/20/decoupling-html-from-css以及作者相关信息

——作者:

——译者:Jekst

多年以来,web标准社区一直在讨论关注点——分离。把CSS样式规则从javascript代码和HTML结构里分离出来。我们确实是这么做的,不是吗?CSS规则放到了独立的文件里,javascript代码放到了另一个独立的文件里,HTML文件就只剩下HTML结构了,这样做既简洁又美观。

CSS Zen Garden向我们证明了我们只需要改变CSS样式文件就能将一个设计转变成多种样式的设计。但是,我们很少注意到这样做的另一面——一个工程里出现这种情况的可能性很大:HTML文档结构的改变。当我们修改了HTML文件后,我们不得不回过头来从新修改CSS文件来适应新的HTML文件。

由此看来,我们并没有真正的将HTML和CSS分开,不是吗?我们不得不在HTML和CSS两个文件里都做修改。

探索方法

在我的职业生涯中,我很高兴能够参与数百个不同的网站和web应用程序的开发。在绝大多数的项目中,我是唯一一个编写HTML和CSS的开发者。我开发了一种开发网站的方法,对我来说,这种方法很好用。

最近两年的时间,我从事于雅虎,参与了 Mail、Messenger、Calendar及其他一些项目的开发。和一个较大的团队一起开发一个较大的项目是一次很棒的经历。一个小团队设计员与一个大团队样式设计师们合作, 为多个团队的工程师建立所有的HTML和CSS。

从多个方面来看,这是我参与过的规模最大的工程:

  • 雅虎拥有大量的用户,仅邮箱用户就达到3亿左右。
  • 遍布多个团队的数百人从事HTML和CSS开发。
  • 我们开发的组件系统在多个工程间使用

就是在雅虎工作期间,我开始真正的考虑我和团队该怎样去构建网站。我们遇到过哪些难题,又能如何避免他们?

我看过其他人的做法, Nicole Sullivan的Object-Oriented CSS,Jina Bolton的“CSS Workflow” ,和Natalie Downe的“Practical, Maintainable CSS”,还有别人的一些文章,这里只列出了一部分。

根据我的想法,我写了一本关于长表单样式的指南,叫做“Scalable and Modular Architecture for CSS”名字有点长,大家可以简称为“SMACSS”(发音“smacks”)。在我提炼并扩张开发CSS渠道的同时,这份指南也会随之继续扩展用于css开发。

结果我发现设计师(包括我)写得CSS规则和被应用样式的HTML有很大关联。为了更少重构、更灵活开发,我们怎么将HTML和CSS分离呢?

换句话说,在任何元素上,我们怎样避免使用!important,或者避免掉进选择器的陷阱呢?

复用样式

以前,我们给需要加样式的HTML元素使用font标签、应用background属性(指attributes,不是CSS里的background属性,是HTML 标签里的background)。当然,这种方式非常不现实, 因此就出现了CSS。CSS能够使我们从页面的一个部分复用另一部分的样式,实现样式的复用。

比如,一个导航菜单,有一些样式一样的菜单项,在每个项使用行样式是不现实的。因此,我们开始看到的CSS是这样的:

#nav {
   margin: 0;
   padding: 0;
   list-style: none;
}

#nav li {
   float: left;
}

#nav li a {
   display: block;
   padding: 5px 10px;
   background-color: blue;
}	

无疑每个菜单项添加了float:left属性,链接加上了display:block; padding:5px 10px;样式。很高效,我们要的效果达到了。看到这些CSS规则,大家就可以看到预期的HTML结构:

<ul id="nav">
  <li><a href="/">Home</a></li>
  <li><a href="/products">Products</a></li>
  <li><a href="/contact">Contact Us</a></li>
</ul>	

现在,客户反馈说:“当点击‘Products‘菜单项的时候,我想要一个下拉的子菜单。并且要在每个页面加上这样的效果!”因此,我们的HTML结构变了:

<ul id="nav">
  <li><a href="/">Home</a></li>
  <li><a href="/products">Products</a>
    <ul>
      <li><a href="/products/shoes">Shoes</a></li>
      <li><a href="/products/jackets">Jackets</a></li> 
    </ul>
  </li>
  <li><a href="/contact">Contact Us</a></li>
</ul>	

现在,Products有了一个子菜单,子菜单里也有连接。我们的菜单是一个水平的导航,但是客户还要一个垂直的下拉菜单,所以我们给子菜单添加一些CSS规则以满足客户的需求。

#nav ul {
  margin: 0;
  padding:0;
  list-style:none;
}

#nav li li {
  float: none;
}

#nav li li a {
  padding: 2px;
  background-color: red;
}	

从某种程度上说,问题解决了。

减少适用性深度

可能使用CSS最常见的问题就是管理特定的样式。页面上会有多个CSS样式规则给一个特定的元素添加样式。像我们的菜单,初始的规则会给导航和下拉菜单里的菜单项和链接都加上样式。这样做并不好。

通过添加额外的元素选择器,我们可以添加特定的样式,使我们的菜单样式不再继承导航的样式。

但是,随着项目复杂程度的增加,这会变得跟猫捉老鼠的游戏一样,不知道哪个元素用的哪个样式。因此我们应该限制CSS规则的影响范围。导航样式应该只应用到属于导航的元素,对这些导航元素产生效果;菜单样式应该应用到属于菜单的元素,对这些菜单元素产生效果。

我在SMACSS中提到过这个影响 - “适应性深度”。 意思是一组特别的规则影响周围元素的深度。例如,当HTML结构包括我们的菜单时,一个像#nav li a这样的样式规则有5个层次的深度:从最外层的ul 到li,到里面的ul,li,a。

适用性层次越深,HTML的元素受到这种样式的影响越大,HTML和CSS的耦合程度越高。

大多数管理CSS的目标——特别是在较大的工程里,是限制适用性的深度。换句话说,写的CSS样式规则只对我们要应用的元素产生效果。

子选择器

一个限制CSS规则作用范围的工具就是子选择器(>)。如果不关心IE6(还好,我们大多数都不关心IE6),子选择器应该是CSS中一个常规的部分。

子选择器限制了选择器的范围。回过头看看我们的导航例子,我们使用子选择器来限制导航样式的范围,这样才不会影响菜单。

#nav {
  margin: 0;
  padding: 0;
  list-style: none;
}

#nav > li {
  float: left;
}

#nav > li > a {
  display: block;
  padding: 5px 10px;
  background-color: blue;
}	

对于子菜单,我们添加一个类选择器。这样使子菜单更具有描述性,并且为菜单的其他部分提供了一个基本的样式。

.menu {
  margin: 0;
  padding: 0;
  list-style: none
}

.menu > li > a {
  display: block;
  padding: 2px;
  background-color: red;
}	

我们所做的就是限制CSS规则的作用范围,将两个不同的视觉效果分成两个单独的CSS块:一个用于导航列表,一个用于子菜单。我们已经向模块化代码和解耦HTML和CSS迈了一小步。

分类代码

限制适用性的深度有助于最小化一个样式对HTML文档中层次较深的元素的影响。但是,还有一个问题就是,我们在CSS中使用了元素选择器,这样做的结果是依赖的HTML结构将永远不能改变,一旦改变,这些样式规则就会不起作用。在导航和菜单这个例子中,总是一个有很多列表项(li)的列表(ul),每个列表项(li)都包含一个链接。这些模块缺乏灵活性。

我们看一个在很多设计中经常见到的例子:一个box,包含一个标题块和一内容区域。

<div class="box">
  <h2>Sites I Like</h2>
  <ul>
    <li><a href="http://smashingmagazine.com/">Smashing Magazine</a></li>
    <li><a href="http://smacss.com/">SMACSS</a></li>
  </ul>
</div>	

我们给这个例子加点样式。

.box {
  border: 1px solid #333;
}

.box h2 {
  margin: 0;
  padding: 5px 10px;
  border-bottom: 1px solid #333;
  background-color: #CCC;
}

.box ul {
  margin: 10px;
}	

客户反馈说:“这个box很好,能不能再添加另一个有关这个网站的box。

<div class="box">
  <h2>About the Site</h2>
  <p>This is my blog where I talk about only the bestest things in the whole wide world.</p>
</div>	

在前一个例子中,为了和上面标题对齐,列表设置了magin属性。对这个新的例子,我们也需要添加类似的样式。

.box ul, .box p {
  margin: 10px;
}	

如果box里的内容部分(这里指的是内容标签,如p,ul等,不是里面的内容)不再变化,这样做完全可以。但是,这个练习的关键点是要意识到网站的结构和内容是会变的。因此,我们不得不看的远点,并且要意识到有很多我们可能会使用的替代的元素。

为了让它灵活点,我们使用class定义这个模块的不同部分。

.box .hd { }  /* this is our box heading */
.box .bd { }  /* this is our box body */	

当应用到HTML上是,就像这样:

<div class="box">
  <h2 class="hd">About the Site</h2>
  <p class="bd">This is my blog where I talk about only the bestest things in the whole wide world.</p>
</div>	

说明意图

页面的不同元素可能包含一个标题部分和一个内容部分。由于他们是box的子选择器元素,他们的样式不受其他样式的影响。但是当我们看HTML时,这些类的意图并不是很明显。所以我们应该表明在box模块中添加的hd 和bd特殊类的意图。

.box .box-hd {}
.box .box-bd {}	

有了这个改进的命名约定,在命名CSS选择器时就不需要组合选择器了。最后的CSS是这样的:

.box {
  border: 1px solid #333;
}

.box-hd {
  margin: 0;
  padding: 5px 10px;
  border-bottom: 1px solid #333;
  background-color: #CCC;
}

.box-bd {
  margin: 10px;
}	

这样做的好处就是每个规则只对那个应用了该规则的元素起作用,CSS也变得容易阅读,容易调试了。什么元素应用什么样式规则,什么样式在起作用,都清清楚楚的。

还没有结束

我么仅看了两种分离HTML和CSS的方法

  1. 使用子选择器
  2. 使用类选择器

除此之外,我们还看到了命名约定,使得代码更清晰、快速、简洁、更容易理解。

还有一些概念,我在Scalable and Modular Architecture for CSS这篇文章中提到了,希望大家去读一读,了解更多。

附言

除了上面的连接资源外,大家不妨去看看BEM的相关资料,它是一个建立维护CSS的另一个框架。Mark Otto已经编写了Twitter Bootstrap的开发文档,包括最近发表的跟限制样式作用范围相似的文章 “Stop the Cascade”。

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

关于Jekst

常用昵称jekst,目前就职于北京一家信息技术公司,主要从事。net系列的开发,热爱前端,对css、jQuery有浓厚兴趣,喜欢参加技术交流活动。欢迎交流共勉:新浪微博

如需转载烦请注明出处:

英文原文:http://coding.smashingmagazine.com/2012/04/20/decoupling-html-from-css

中文译文:http://www.w3cplus.com/css/decoupling-html-from-css.html

返回顶部