在我們開(kāi)始之前,先搞明白幾個(gè)概念吧。下面是一段CSS代碼:
a {
border-bottom: 0px;
color: #5DB0E6;
}
a:focus {
outline: 1px dotted #eee;
}
a:active {
outline: 0px;
}
a:hover {
color: #7bc4f4;
}
body#jq-interior {
background-image: url(http://static.jquery.com/files/rocker/images/bg-interior-tile-drk.jpg);
}
上面這個(gè)樣式表是由一個(gè)個(gè)樣式規(guī)則組成,而每一個(gè)樣式規(guī)則又可以分為兩部分:選擇符與聲明。選擇符就相當(dāng)于jQuery的選擇器,能針對(duì)特定元素進(jìn)行設(shè)置。CSS有名叫層疊樣式表,基本上被選中的元素的子元素能繼承它的樣式,但其子元素如果設(shè)置了樣式,也能覆寫(xiě)它,就像板頁(yè)巖這樣累在一起。隨著布局表格這樣落后的布局方式的式微,CSS越來(lái)越受到人們的重視。但I(xiàn)E6對(duì)CSS的支持不足與各種層不窮的bug,或者是某些大型網(wǎng)站對(duì)CSS的不合理使用,CSS的體積膨脹起來(lái)了。維護(hù)它們可是一件麻煩事,如何讓元素顯示出想要的樣式,我們就必須對(duì)權(quán)重這個(gè)概念有所了解。權(quán)重你可以說(shuō)是針對(duì)樣式規(guī)則的,也可以說(shuō)針對(duì)選擇符。之所以這樣說(shuō),因?yàn)橛幸粋(gè)重要的標(biāo)識(shí)符! important可以放到樣式聲明的最后,用來(lái)無(wú)視本文重點(diǎn)說(shuō)的權(quán)重等級(jí)。我覺(jué)得最好還是不要用這東西,首先IE6對(duì)它支持不好,要支持它需要把一個(gè)樣式規(guī)則分開(kāi)寫(xiě),另,用多了會(huì)嚴(yán)重?cái)_亂CSS的權(quán)重等級(jí)。
有關(guān)CSS權(quán)重等級(jí)的介紹最早見(jiàn)于W3C這篇文章,聽(tīng)說(shuō)IE5是最早支持CSS的,不知哪個(gè)早一點(diǎn)呢?很明顯IE是沒(méi)有完全照足它來(lái)實(shí)現(xiàn)。在《Calculating a selector's specificity》一章,它粗略地用a、b、c、d來(lái)對(duì)樣式規(guī)則進(jìn)行評(píng)估,給出每一個(gè)的得分(1 或 0),但沒(méi)有給出最終值的計(jì)算方式。
a:如果這個(gè)元素應(yīng)用了行內(nèi)樣式,它才分配此值為1。怎么是行內(nèi)樣式呢?就是標(biāo)簽內(nèi)使用style="...."的方式來(lái)設(shè)置樣式,我覺(jué)得這是很愚蠢的行為,徒然增加頁(yè)面的體積,也非常不好維護(hù),和使用那些純表示樣式的元素差不多,如big、small、b、u、strike 等等。這樣做法,我個(gè)人覺(jué)得,瀏覽器其實(shí)是為它分配了一個(gè)特別的ID(實(shí)質(zhì)上IE也是為頁(yè)面上每個(gè)元素分配了一個(gè)uniqueId),然后把它置于樣式表的最下方,于是就沒(méi)有其他樣式能覆蓋它了。
b:指一個(gè)樣式規(guī)則的選擇符存在id選擇器。比如上面的body#jq-interior ,不過(guò)這樣有點(diǎn)累贅了。我看了許多CSS選擇器的實(shí)現(xiàn),還有我在做選擇器的經(jīng)驗(yàn),body完全沒(méi)有必要。一個(gè)選擇符就相當(dāng)于一個(gè)選擇器群組,它由各種各樣的選擇器組成。選擇器得到一個(gè)符合CSS選擇符結(jié)構(gòu)的字符串,如果它足夠聰明的話(huà),會(huì)先對(duì)字符串進(jìn)行trim操作,然后進(jìn)行掃描,看有沒(méi)有id選擇器,有的話(huà)會(huì)砍掉前面的部分,然后再用正則對(duì)其進(jìn)行肢解……換言之,id選擇器具有強(qiáng)烈的排它性,只有并聯(lián)選擇器可以容忍它。
c:指一個(gè)樣式規(guī)則的選擇符是否存在類(lèi)選擇器與偽類(lèi)選擇器(:hover,:link,:active,:target)。這些基本上CSS2.1的東西,CSS3增加的基本是結(jié)構(gòu)偽類(lèi)還有一個(gè)selection偽元素,沒(méi)有破壞這個(gè)評(píng)分體系。
d:這個(gè)權(quán)重最低了,指選擇符里存在標(biāo)簽選擇器,與偽元素。何為偽元素呢?前面有::的東西就是偽元素了。注意,早期的偽元素也和偽類(lèi)一樣,只有一個(gè)冒號(hào)。這可能是后來(lái)w3c心血來(lái)潮,把它們分離出來(lái)(css3規(guī)范),造成今天的樣子。
雖然到目前為止,我們已經(jīng)知道a的權(quán)重肯定大于b,而b大于c,d最小,但這實(shí)在不好計(jì)算,對(duì)于接著下來(lái)的示例也不好解說(shuō)。于是我引進(jìn)外國(guó)另一個(gè)補(bǔ)充方案,它出于這篇名叫《CSS: Specificity Wars》的有才文章。。它把a(bǔ)bcd當(dāng)成算術(shù)上的個(gè)、十、百、千這樣的計(jì)數(shù)單位,各自相乘最后一加,優(yōu)先級(jí)就一目了然啦。我們甚至可以將它們轉(zhuǎn)化為以下一個(gè)直觀(guān)的圖示。
好了,我們開(kāi)始分析一下w3c的示例,看它能給我們什么多余的信息。
/*by 司徒正美 All rights reserve*/
* {} /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
/* 通配符選擇器權(quán)重為0,在IE中,它無(wú)法區(qū)分元素節(jié)點(diǎn)與注釋節(jié)點(diǎn) */
li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
/* 標(biāo)簽選擇器為1 */
li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
/* 標(biāo)簽選擇器與偽元素為1 */
ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
/*這里存在后代選擇器的概念,但計(jì)算權(quán)重時(shí)像它這樣的關(guān)系選擇器會(huì)被進(jìn)一步肢解,當(dāng)成兩個(gè)標(biāo)簽選擇器了。*/
ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
/* 無(wú)視后代選擇器與相鄰選擇器,只看它里面的選擇器的成分 */
h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
/* 這個(gè)相鄰選擇器由標(biāo)簽選擇器與屬性選擇器組成,屬性選擇器為10 */
ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
/*無(wú)視后代選擇器,3個(gè)標(biāo)簽與1個(gè)類(lèi)選擇器,類(lèi)(className)在DOM中的位置比較顯赫,
擁有專(zhuān)門(mén)的getElementByClassName,等級(jí)為c,合計(jì)得分13 */
li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
/*兩個(gè)類(lèi)選擇器與一個(gè)標(biāo)簽選擇器,合計(jì)得分21 */
#x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
/*getElementById,在頁(yè)面上獲得元素最快的方式,權(quán)重為b,得分100 */
style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */
/*行內(nèi)樣式,得分1000,會(huì)覆蓋內(nèi)部樣式或外部樣式的設(shè)置*/
最后總結(jié)一下,十大選擇器與偽元素的權(quán)重情況: