即使在不太复杂的样式表中,要寻找同一元素可能有两个或更多规则。CSS通过一个称为层叠(cascade)的过程处理这种冲突。层叠给每个规则分配一个重要度。作者的样式表是由站点开发者编写的,被认为是最重要的样式表。用户可以通过浏览器应用自己的样式,这些样式表的重要度低一级。最后是浏览器或用户代理使用的默认样式表,它们的重要度是最低的,所以你总是可以覆盖它们。为了让用户有更多的控制能力,可以通过将任何规则指定为!important来提高它的重要度,让它优先于任何规则,甚至优先于作者加上!important标志的规则。这种设置能够满足特殊的可访问性需求,例如如果用户有某种读写障碍,可以使用中等对比度的用户样式表。
因此,层叠采用以下重要度次序。
标有!important的用户样式。
标有!important的作者样式。
作者样式。
用户样式。
浏览器/用户代理应用的样式。
然后,根据选择器的特殊性决定规则的次序。具有更特殊选择器的规则优先于具有一般选择器的规则。如果两个规则的特殊性相同,那么后定义的规则优先。
1. 特殊性
为了计算规则的特殊性,给每种选择器都分配一个数字值。然后,将规则的每个选择器的值加在一起,计算出规则的特殊性。可惜特殊性的计算不是以10为基数的,而是采用一个更高的未指定的基数。这能确保非常特殊的选择器(比如ID选择器)不会被大量一般选择器(比如类型选择器)所超越。但是,为了简化,如果在一个特定选择器中的选择器数量少于10个,那么可以以10为基数计算特殊性。
选择器的特殊性分成4个成分等级:a、b、c和d。
如果样式是行内样式,那么a = 1。
b等于ID选择器的总数。
c等于类、伪类和属性选择器的数量。
d等于类型选择器和伪元素选择器的数量。
使用这些规则可以计算任何CSS选择器的特殊性。表2-1给出了一系列选择器以及相应的特殊性。
表2-1 特殊性示例
选 择 器 | 特 殊 性 | 以10为基数的特殊性 |
Style="" | 1,0,0,0 | 1000 |
#wrapper #content {} | 0,2,0,0 | 200 |
#content .datePosted {} | 0,1,1,0 | 110 |
div#content {} | 0,1,0,1 | 101 |
#content {} | 0,1,0,0 | 100 |
p.comment .dateposted {} | 0,0,2,1 | 21 |
p.comment{} | 0,0,1,1 | 11 |
div p {} | 0,0,0,2 | 2 |
p {} | 0,0,0,1 | 1 |
初看上去,上面的特殊性和更高的未指定的基数可能有点儿让人糊涂,所以再解释一下。基本上,用style属性编写的规则总是比其他任何规则特殊。具有ID选择器的规则比没有ID选择器的规则特殊,具有类选择器的规则比只有类型选择器的规则特殊。最后,如果两个规则的特殊性相同,那么后定义的规则优先。
在修复bug时特殊性极其重要,因为你需要了解哪些规则优先及其原因。例如,假设有以下这组规则,你认为两个标题会是什么颜色的?
- #content div#main-content h2 {
- color: gray;
- }
- #content #main-content>h2 {
- color: blue;
- }
- body #content div[id="main-content"] h2 {
- color: green;
- }
- #main-content div.news-story h2 {
- color: orange;
- }
- #main-content [class="news-story"] h2 {
- color: yellow;
- }
- div#main-content div.news-story h2.first {
- color: red;
- }
- <div id="content">
- <div id="main-content">
- <h2>Strange Times</h2>
- <p>Here you can read bizarre news stories from around the globe.</p>
- <div class="news-story">
- <h2 class="first">Bog Snorkeling Champion Announced Today</h2>
- <p>The 2008 Bog Snorkeling Championship was won by Conor Murphy
- with an impressive time of 1 minute 38 seconds.</p>
- </div>
- </div>
- </div>
令人吃惊的是,两个标题都是灰色的。第一个选择器由两个ID选择器组成,因此它具有最高的特殊性。后面一些选择器看起来更复杂,但是因为它们只包含一个ID,所以特殊性总是低于第一个选择器。
如果你遇到了似乎没有起作用的CSS规则,很可能是出现了特殊性冲突。请在你的选择器中添加它的一个父元素的ID,从而提高它的特殊性。如果这能够解决问题,就说明样式表中其他地方很可能有更特殊的规则,它覆盖了你的规则。如果是这种情况,你可能需要检查代码,解决特殊性冲突,让代码尽可能简洁。
2. 在样式表中使用特殊性
在编写CSS时特殊性非常有用,因为它可以对一般元素应用一般样式,然后在更特殊的元素上覆盖它们。例如,如果你希望站点上大多数文本是黑色的,但介绍说明文本是灰色的。可以这样做:
- p {color: black;}
- p.intro {color: grey;}
对于小网站,这很好。但是,在大型站点上,你会发现例外情况越来越多。例如,你可能希望新闻文章上的介绍文本是蓝色的,而主页上的介绍文本使用灰色背景。每当创建更特殊的样式时,可能需要覆盖一些一般规则。这可能需要一些额外的代码。而且,因为元素可以从许多地方获得样式,情况可能变得非常复杂。
为了避免过分混乱,我尽量保持一般性样式非常一般,特殊样式尽可能特殊,这样就不需要覆盖特殊样式了。如果发现不得不多次覆盖一般样式,那么从更一般的规则中删除需要覆盖的声明,并且将它显式地应用于需要它的每个元素,这样可能比较简单。
3. 在主体标签上添加类或ID
一种有意思的特殊性用法是在主体(body)标签上应用类或ID。这样做之后,就可以根据页面或在站点范围内覆盖样式。例如,如果希望新的页面具有特殊的布局,那么可以在主页的主体元素上添加一个类名,并且使用它覆盖样式:
- body.news {
- /* do some stuff */
- }
- <body class="news">
- <p>My, what a lovely body you have.</p>
- </body>
有时候,在特殊页面上需要覆盖这些样式,比如在新闻存档页面上。在这种情况下,可以在主体标签上添加ID来标识这个页面。
- body.news {
- /* do some stuff */
- }
- body#archive {
- /* do some different stuff */
- }
- <body id="archive" class="news">
- <p>My, what a lovely body you have.</p>
- </body>
使用类标识页面类型,使用ID标识特定页面,就可以非常灵活地控制站点的设计和布局。我很喜欢使用这种方法编写可维护的代码。