前面我們介紹了如何利用網(wǎng)頁文檔結(jié)構(gòu)和CSS選擇器為元素應用各種豐富的樣式。每個合法的文檔都會生成一個結(jié)構(gòu)樹,了解了這一點,就能根據(jù)元素的祖先、屬性、兄弟元素等等創(chuàng)建選擇器來選擇元素。有了這個結(jié)構(gòu)樹,選擇器才能起作用,這也是CSS另一個重要方面(即繼承)的核心。
繼承(Inheritance)是從一個元素向其后代元素傳遞屬性值所采用的機制。確定應當向一個元素應用哪些值時,網(wǎng)頁瀏覽器不僅要考慮繼承,還要考慮聲明的特殊性,另外需要考慮聲明本身的來源。這個過程就稱為層疊(cascade)。我們接下來將討論這3種機制之間的關(guān)聯(lián):特殊性、繼承和層疊。
特殊性
我們現(xiàn)在知道了可以使用多種不同的方法選擇元素。實際上,可能同一個元素可以使用兩個或多個規(guī)則來選擇,每個規(guī)則都有其自己的選擇器,下面考慮以下3對規(guī)則。假設每一對規(guī)則都匹配同樣的元素:
h1 {color: red;}
body h1 {color: green;}
h2.grape {color: purple;}
h2 {color: silver;}
html > body table tr[id="totals"] td ul > li {color: maroon;}
li#answer {color: navy;}
顯然,每一對規(guī)則中只有一個勝出,因為所匹配的元素只能是某一種顏色(或此或彼)。那么怎么知道哪一個規(guī)則更強呢?
答案就在于每個選擇器的特殊性(specificity)。對于每個規(guī)則,用戶代理會計算選擇器的特殊性,并將這個特殊性附加到規(guī)則中的各個聲明。如果一個元素有兩個或多個沖突的屬性聲明,那么有最高特殊性的聲明就會勝出。
注意:這并不是解決沖突的全部。實際上,所有樣式?jīng)_突的解決都由層疊來處理,本章后面專設了一節(jié)介紹這個內(nèi)容。
選擇器的特殊性由選擇器本身的組件確定。特殊性值表述為4個部分,如:0,0,0,0。一個選擇器的具體特殊性如下確定:
對于選擇器中給定的各個ID屬性值,加0,1,0,0。
對于選擇器中給定的各個類屬性值,屬性選擇或偽類,加0,0,1,0。
對于選擇器中給定的各個元素和偽元素,加0,0,0,1。偽元素是否有特殊性,在這方面css2有些自相矛盾,不過css2.1很清楚的指出,偽元素有特殊性,而且其特殊性為0,0,0,1。
結(jié)合符和通配符選擇器對特殊性沒有任何貢獻(后面還會更多地介紹這些值)。
例如,以下規(guī)則中選擇器的特殊性見注釋:
h1{color:red;}/* specifity = 0,0,0,1 */
p em{color:purple;}/* specifity = 0,0,0,2 */
.grape{color:purple;}/* specifity = 0,0,1,0 */
*.bright{color:yellow;}/* specifity = 0,0,1,0 */
p.bright em.dark{color:maroon;}/* specifity = 0,0,2,2 */
#id216{color:blue;}/* specifity = 0,1,0,0 */
div#sidebar *[href]{color:silver;}/* specifity = 0,1,1,1 */
假設有以下情況,一個em元素與上例中的第2條規(guī)則匹配,又與第5條規(guī)則匹配,這個元素將是紫紅色,因為第5條規(guī)則的特殊性高于第2條規(guī)則的特殊性。
下面做個練習,回顧本節(jié)前面給出的幾組規(guī)則,看看它們有怎樣的特殊性:
h1 {color:red;}/* 0,0,0,1 */
body h1 {color:green;}/* 0,1,0,2 (winner)*/
h2.grape{color:purple;}/* 0,0,1,1 (winner)*/
h2 {color:silver;}/* 0,0,0,1 */
html > body table tr[id="totals"] td ul > li {color: maroon;}/* 0,0,1,7 */
li#answer {color: navy;}/* 0,1,0,1 (winner)*/
上面已經(jīng)指出每組規(guī)則中的勝出規(guī)則,在上述各種情況下,那些規(guī)則之所以勝出是因為其特殊性更高。要注意特殊性是如何排序的。在第二組中,選擇器h2.grape能“贏”是因為它多了一個1: 0,0,1,1大于0,0,0,1。在第三組中,第二個規(guī)則勝出是因為0,1, 0,1大于0,0,1,7。實際上,特殊性值0,0,1,0比值0,0, 0,13更高。
之所以會這樣,是因為值是從左向右排序的。特殊性值1,0, 0,0大于以0開頭的所有特殊性值,而不論后面的數(shù)是什么。所以0,1, 0,1比0,0,1,7高,因為前一個值中第二位上的1大于第二個值中第二位上的0。
一旦確定一個選擇器的特殊性,這個值將授予其所有相關(guān)聲明??紤]以下規(guī)則:
h1 {color: silver; background: black;}
由于特殊性的緣故,網(wǎng)頁瀏覽器必須相應地處理這個規(guī)則,將其“解組”為單獨的規(guī)則。因此,前面的例子將變成:
h1 {color: silver;}
h1 {background: black;}
這兩個規(guī)則的特殊性都是0, 0 , 0 , 1,各聲明得到的特殊性值也就是0, 0 , 0 , 1。分組選擇器也同樣會完成這種分解過程。給定以下規(guī)則:
h1, h2.section {color: silver; background: black;}
網(wǎng)頁瀏覽器將把它處理為:
h1 {color: silver;}/* 0,0,0,1 */
h1 {background: black;}/* 0,0,0,1 */
h2.section {color: silver;}/* 0,0,1,1 */
h2.section {background: black;}/* 0,0,1,1 */
如果多個規(guī)則與同一個元素匹配,而且有些聲明相互沖突,在這種情況下特殊性就很重要。例如,考慮以下規(guī)則:
h1 + p {color: black; font-style: italic;}/* 0,0,0,2 */
p {color: gray; background: white; font-style: normal;}/* 0,0,0,1 */
*.aside {color: black; background: silver;}/* 0,0,1,0 */
當這些規(guī)則應用到以下標記時,顯示的內(nèi)容將如圖3-1所示:
<h1>Greetings!</h1>
<p class="aside"> It's a fine way to start a day, don't you think?
</p>
<p> There are many ways to greet a person, but the words are not as important as the act of greeting itself.
</p>
<h1>Salutations!</h1>
<p> There is noth1ng finer than a hearty welcome from one's fellow man.
</p>
<p class="aside"> Although a thick and juicy hamburger with bacon and mushrooms runs a close second.
</p>
任何情況下,用戶代理都會確定哪些規(guī)則與一個元素匹配,計算出所有相關(guān)的聲明及其特殊性,確定哪些規(guī)則勝出,然后將勝出的規(guī)則應用到元素,從而得到應用樣式后的結(jié)果。每個元素、選擇器和聲明上都必須完成這些工作。幸運的是,用戶代理會自動完成所有這些工作。這個行為是層疊的一個重要部分,本章后面還將深入討論層疊。
前面提到過,通配選擇器對一個選擇器的特殊性沒有貢獻。換句話說,其特殊性為0,0,0,0,這與根本沒有特殊性有區(qū)別(有關(guān)內(nèi)容將在“繼承”一節(jié)中介紹)。因此,給定以下兩條規(guī)則,div下包含的段落將是黑色,而其他元素都是灰色:
div p {color: black;}/* 0,0,0,2 */
*{color: gray;}/* 0,0,0,0 */
如你所料,這意味著如果一個選擇器中包含通配選擇器和其他選擇器,該選擇器的特殊性不會因通配選擇器的出現(xiàn)而改變。下面兩個選擇器的特殊性完全相同:
div p /* 0,0,0,2 */
body * strong /* 0,0,0,2 */
相比之下,結(jié)合符則根本沒有特殊性,甚至連0特殊性都沒有。因此,它們對選擇器的總特殊性沒有任何影響。
ID和屬性選擇器的特殊性
需要著重指出,ID選擇器和指定id屬性的屬性選擇器在特殊性上有所不同。再來看示例代碼中的第三組規(guī)則,可以看到:
html > body table tr[id="totals"] td ul > li {color: maroon;}/* 0,0,1,7 */
li#answer {color: navy;}/* 0,1,0,1 {winner}*/
第二個規(guī)則中的ID選擇器(#answer)為選擇器的總特殊性貢獻了0,1, 0,0。而在第一個規(guī)則中,屬性選擇器([id="totals"])只對總特殊性貢獻了0,0,1,0。因此,給定以下規(guī)則,id為meadow的元素將變成綠色:
#meadow {color: green;}/* 0,1,0,0 */
*[id:"meadow"]{color: red;}/* 0,0,1,0 */
到目前為止,我們已經(jīng)見過以0開頭的特殊性,所以你可能會奇怪為什么會有這些特殊性。一般地,第一個0是為內(nèi)聯(lián)樣式聲明保留的,它比所有其他聲明的特殊性都高??紤]以下規(guī)則和標記片段:
h1 {color: red;}
<h1 style="color: green?">The Meadow Party</h1>
假設這個規(guī)則應用到h1元素,h1的文本還將是綠色。CSS2.1中就是如此,這是因為每個內(nèi)聯(lián)聲明的特殊性都是1,0, 0,0。
這意味著,即使有id屬性的元素與某個規(guī)則匹配,也必須遵循內(nèi)聯(lián)樣式聲明。下面把上例修改為包括一個id屬性:
h1#meadow {color: red;}
<h1 id="meadow" style="color: green;">The Meadow Party</h1>
由于內(nèi)聯(lián)聲明的特殊性最高,h1元素的文本還是綠色。
注意:為內(nèi)聯(lián)樣式聲明保留一位,這是CSS2.1才新增的,這樣做是為了反映寫CSS2.1當時的Web 瀏覽器表現(xiàn)。在CSS2中,內(nèi)聯(lián)樣式聲明的特殊性是1,0,0 (CSS2特殊性包含3個值,而不是4個)。換句話說,它與ID選擇器的特殊性相同,所以ID選擇器很容易覆蓋內(nèi)聯(lián)樣式。
重要性
有時某個聲明可能非常重要,超過了所有其他聲明。CSS2.1稱之為重要聲明(原因顯而易見),并允許在這些聲明的結(jié)束分號之前插入!important來標志。
p.dark {color:#333 !important; background: white;}
在此為顏色值#333加了標志!important,而背景值white未加這個標志。如果你希望把兩個聲明都標志為重要,那么每個聲明都需要它自己的!important標志:
p.dark {color:#333 !important; background: white !important;}
必須正確地放置!important,否則聲明將無效。! important總是放在聲明的最后,即分號前面。如果一個屬性的值可以包含多個關(guān)鍵詞,如font,這一點則尤其重要,必須將!important標志放在聲明的最后:
p.light {color: yellow; font: smaller Times, serif !important;}
如果!important放在font聲明的任何其他位置,整個聲明都將無效,相應地不會應用其任何樣式。
標志為!important的聲明并沒有特殊的特殊性值,不過要與非重要聲明分開考慮。實際上,所有!important聲明會分組在一起,重要聲明的特殊性沖突會在重要聲明內(nèi)部解決,而不會與非重要聲明相混。類似地,我們認為所有非重要聲明也歸為一組,使用特殊性來解決沖突。如果一個重要聲明和一個非重要聲明沖突,勝出的總是重要聲明。圖3-2展示了以下規(guī)則和標記片段的結(jié)果:
h1 {font-style: italic; color: gray !important;}
.title {color: black; background: silver;}
*{background: black !important;}
<h1 class="title">NightWing</h1>
當前文章標題:網(wǎng)頁的結(jié)構(gòu)和重疊
當前URL:http://www.gtalker.cn/news/wzzz/Structure-and-overlap-of-web-pages.html