# 适用性深度

学习CSS时,我们知道选择器可以选择对应元素,然后编写对应的样式。CSS不断成长,选择器也不断增加,我们发挥余地也越来越大。不过,我们设置的样式越多,CSS和HTML之间的联系就越紧密。

我们来看一个典型的CSS代码块,你可以在某个站点上能够找到。

/* 我们是如何将我们CSS和HTML紧密联系在一起 */
#sidebar div {
    border: 1px solid #333;
}

#sidebar div h3 { 
    margin-top: 5px;
}

#sidebar div ul {
    margin-bottom: 5px; 
}

看上面例子,你可能会发现,代码对HTML的结构是有一些预期的:sidebar应该有几个部分,而每个部分中可能有一个标题和一个无序的列表。如果站点不经常改变,上述CSS样式可能是OK的。比如我已经两年没有对我博客的设计有任何改变了,因为博客的扩展需求不大。但如果我尝试使用这种方法在更大的网站上,这个网站改变十分频繁,并且有很多不同的代码需求,那可能我就会遇到麻烦了。我可能需要添加更多有更复杂的选择器的规则,那时我可能会发现自己处于维护噩梦中。

我哪里弄错了呢?这个CSS例子中主要有两点需要特别关注的:

  1. 十分依赖定义好的HTML结构
  2. 选择器应用HTML结构的深度过深了

# 最小化深度

HTML是一颗有父节点和子节点的树。适用性的深度是特定规则影响的层次数量。例如,body.article > #main > #content > #intro > p > b的适用性深度是6,如果我们把它写成.article #intro b,深度还是相同,同样是6。

这样的深度的问题主要是它使得我们对特定HTML结构的依赖更深了。页面上的组件不能被简单地转移使用。如果我们回顾下sidebar的例子,想下,我们怎么样在页面的另外部分(比方说footer)创建一个这样的模块?我们必须重复这些规则!

/* 规则的重复 */
#sidebar div, #footer div {
    border: 1px solid #333;
}

#sidebar div h3, #footer div h3 { 
    margin-top: 5px;
}

#sidebar div ul, #footer div ul {
    margin-bottom: 5px; 
}

根节点在div处,我们从这里创建一个新的类,创建我们的样式。

/* 简化规则 */

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

.pod > h3 { 
    margin-top: 5px;
}

.pod > ul {
    margin-bottom: 5px; 
}

pod是一个容器,它仍然依赖特殊的HTML结构,但是其深度比我们之前的浅多了。但相对的,我们必须在页面的元素上重复pod类名。而之前我们只有两个元素的ID。当然,我们也要避免做在每个段落上添加类名这样的傻事儿。

适用性深度较浅还有一个好处:可以使得把模块转换为动态内容模板更加容易。例如,在雅虎,我们使用Mustache来满足我们的大部分模板需求。下面展示了我们如何为这些pod生成模板。

<!-- 一个Mustache模板 -->
<div class="pod">
    <h3>{{heading}}</h3>
    <ul>
        {{#items}}
        <li>{{item}}</li>
        {{/items}}
    </ul>
</div>

上述例子,我们正努力在维护性,性能,可读性上取得平衡。虽然在HTML中,深度越深意味着类越少(多类症不容易发生),但是它增加了维护成本,减少了可读性。而且你也没必要在所有地方都加上类。在h3或是ul上添加类名是不太必要的,除非你想构造更加灵活的系统。

最后一个例子更进一步讲,是一个普遍的设计模式。就是一个带有headerbody的容器(有时,还会有一个footer)。我们在例子中已经有了一个ul,但在其他例子中,可能会是ol或者是div

我们可能还是为每个类重复规则。

/* 规则重复 */
.pod > ul, .pod > ol, .pod > div {
    margin-bottom: 5px; 
}

也可以为podbody添加类。

/* 用类来简化 */
.pod-body {
    margin-bottom: 5px; 
}

用模块的命名规则,我们都不需要标定.pod。我们可以直观地看到.pod-bodypod模块是关联在一起的,而从代码层面来说,这照样可以很好地工作。

<!-- Mustache模板的例子 -->
<div class="pod">
    <h3>{{heading}}</h3>
    <ul class="pod-body">
        {{#items}}
        <li>{{item}}</li>
        {{/items}}
    </ul>
</div>

这个微小的更改使得适用性深度达到最小。而单个选择器也意味着我们可以避免一些潜在的特殊问题。不管怎么说,都是多赢的方法!