CSS高級選擇器

CSS是對網頁設計師可用的最強大的工具之一。使用它我們可以在幾分鐘內改變一個網站的界面,而不用改變頁面的標籤。但是儘管事實上,我們每個人也 都意識到了它是有用的,CSS 選擇器遠未發揮它們的潛力,有的時候我們還趨向於使用過多的和無用的classiddivspan等把我們的HTML搞的很凌亂。

避免讓這些瘟疫在你的標籤中傳播並保持其簡潔和語義化的最佳方式,就是使用更復雜的CSS選擇器,它們可以定位於指定的元素而不用使用額外的classid,而且通過這種方式也可以讓我們的代碼和樣式更加靈活

CSS的優先級

在深入研究高級CSS選擇器領域之前,理解CSS優先級是如何工作的是很重要的,這樣我們就知道如何適當的使用我們的選擇器並避免浪費大量的時間來調試一些只要我們注意到優先級的話就很容易被搞定的問題

當我們寫CSS的時候我們必須注意有些選擇器在級聯(cascade)上會高於其它選擇器,我們寫在最後面的選擇器將不一定會覆蓋前面我們寫在同一個元素的樣式。

那麼你如何計算指定選擇器的優先級?如果你考慮到將優先級表示爲用逗號隔開的四個數字就會相當簡單,比如:1, 1, 1, 1 0, 2, 0, 1

  1. 第一個數字(a)通常就是0,除非在標籤上使用style屬性;
  2. 第二個數字(b)是該選擇器上的id的數量的總和;
  3. 第三個數字(c)是用在該選擇器上的其它屬性選擇器和僞類的總和。這裏包括class (.example) 和屬性選擇器(比如 li[id=red])
  4. 第四個數字(d)計算元素(就像tablepdiv等等)和僞元素(就像:first-line)
  5. 通用選擇器(*)0優先級;
  6. 如果兩個選擇器有同樣的優先級,在樣式表中後面的那個起作用。

讓我們看幾個例子,這樣或許比較容易理解些:

  • #sidebar h2 — 0, 1, 0, 1
  • h2.title — 0, 0, 1, 1
  • h2 + p — 0, 0, 0, 2
  • #sidebar p:first-line — 0, 1, 0, 2

在下面的例子中,第一個將會起作用,因爲它比第二個優先級高:

  • #sidebar p#first { color: red; } — 0, 2, 0, 1
  • #sidebar p:first-line { color: blue; } — 0, 1, 0, 2

至少基本理解優先級是如何工作的是很重要的,但是一些工具比如Firebug,在我們審查指定元素的時候,按照選擇器的優先級列出所有的css選擇器對讓我們知道在指定元素上哪個選擇器是有效的是很有用的。


讓你非常容易的看到那個選擇器作用於一個元素上了。

有用的文章:

1. 屬性選擇器

屬性選擇器(Attribute selector)讓你可以基於屬性來定位一個元素。你可以只指定該元素的某個屬性,這樣所有使用該屬性——而不管它的值——的這個元素都將被定位,也可以更加明確並定位在這些屬性上使用特定值的元素 —— 這就是屬性選擇器展示它們的威力的地方。

6個不同類型的屬性選擇器:

  • [att=value]
    該屬性有指定的確切的值。
  • [att~=value]
    該屬性的值必須是一系列用空格隔開的多個值,(比如,class=”title featured home”),而且這些值中的一個必須是指定的值”value”
  • [att|=value]
    屬性的值就是“value”或者以“value”開始並立即跟上一個“-”字符,也就是“value-”(比如lang=”zh-cn”)
  • [att^=value]
    該屬性的值以指定值開始。
  • [att$=value]
    該屬性的值包含指定的值(而無論其位置)
  • [att*=value]
    該屬性的值以指定的值結束

比如,如果你想要改變你的博客上的日誌部分元素的背景顏色,你可以使用一個指定每一個class屬性值以“post-”開始的div的屬性選擇器:

div[class|="post"] {

      background-color: #333;

      }

該語句將匹配所有class屬性包含”post”並帶”-”字符的div元素。(注:此處英文原文有些上下文不對應,我已經更正——譯者,神飛)

屬性選擇器的另一個很有用的用處是定位不同類型的input元素。比如,如果你想讓你的文本輸入框使用一個特定的寬度,你可以使用下面的屬性選擇器:

input[type="text"] {

      width: 200px;

      }

這將匹配所有type屬性值等於“text”input元素。

現在我們可能像爲網站上不同的文件類型的鏈接添加不同的圖標,這樣你的網站的訪客就會知道他們將獲得一個圖片、或者PDF文件、或者是一個word文檔等。這就可以使用屬性選擇器來實現:

a[href*=".jpg"] {

      background: url(jpeg.gif) no-repeat left 50%;

      padding: 2px 0 2px 20px;

      }

 

a[href*=".pdf"] {

      background: url(pdf.gif) no-repeat left 50%;

      padding: 2px 0 2px 20px;

      }

 

a[href*=".doc"] {

      background: url(word.gif) no-repeat left 50%;

      padding: 2px 0 2px 20px;

      }

在此例中,我們使用了一個定位所有的鏈接(a)href屬性分別以.jpg,.pdf.doc結束(*)的屬性選擇器。詳細可查看前端觀察之前的一篇文章《使用CSS選擇器創建個性化鏈接樣式

瀏覽器支持

除了Internet Explorer 6,所有的主流瀏覽器都支持屬性選擇器。這意味着,如果你在你的網站上使用了屬性選擇器,你應該確保IE6用戶將仍能獲得一個可用的網站。比如我們的第三個例子,爲鏈接添加圖標可以給你的網站帶來另一個級別的可用性,但是如果這些鏈接不顯示任何圖標,該網站仍然還是可用的。

2. 子選擇器

子選擇器用符號“>”表示。它允許你定位某個元素的第一級子元素

比如,如果你想匹配所有的作爲你的網站側欄的div的子元素的h2元素,而不是可能是在div元素內的所有h2元素,也不是div的孫元素(或者更低級別的),你就可以使用下面的選擇器:

div#sidebar > h2 {

      font-size: 20px;

      }

你當然也可以同時使用子元素和後代元素。比如,如果你想定位只有在body元素的子級div元素內的blockquote元素(比如你想匹配主要的div內的blockquotes,而不是其它部分的:

body > div > div blockquote {

      margin-left: 30px;

      }

瀏覽器支持

和屬性選擇器一樣,子選擇器不被IE6支持。如果你通過這種方式要實現的效果和網站的可用性或總體設計息息相關,你可以考慮使用一個class,或者使用只針對IE6的樣式,但是這將有悖使用子選擇器的目的。

3. 兄弟組合

有兩類兄弟組合:臨近兄弟組合和普通兄弟組合

臨近兄弟組合

該選擇器使用加號“+”來鏈接前後兩個選擇器。選擇器中的元素有同一個父親,而且第二個必須緊緊的跟着第一個

臨近兄弟組合可以灰常有用,比如,在處理文字的時候。比如我們想對段落後面的h2標題添加一個頂間距“margin-top”(當然或許你無需爲h1標籤後面的h2添加,或者它可能是頁面的第一個元素)

p + h2 {

      margin-top: 10px;

      }

你甚至可以更加具體,你想定位某個特定的div後面的h2

div.post p + h2 {

      margin-top: 10px;

      }

或者你可以搞得更加複雜:頁面的第一個段落的第一行字母顯示爲小寫字母。

.post h1 + p:first-line {

      font-variant: small-caps;

      }

因爲可能大部分日誌/文章的第一個段落都會緊緊的在H1標籤的後面。你可以在你的選擇器中藉助於h1標籤。

普通兄弟組合

普通兄弟組合和臨近兄弟組合的工作原理很像,不同的是第二個選擇其無需緊緊跟隨第一個

如果你需要定位所有的某個特定的div裏面並且跟在h1標籤後面的p標籤的話(你可能想要這些p標籤比擬的日誌的標題前面的文字大些),你就可以使用這個選擇器:

.post h1 ~ p {

      font-size: 13px;

      }

注:這兩個選擇器太像了,所有不是很好理解,可以試一試下面的這個例子:

CSS:

p + h2{color:red;

      }

      p ~ h2{font-weight:700;

      }

HTML:

<p>咳咳,內容。</p>

<h2>標題1</h2>

<h2>標題2</h2>

看看第二個h2的顏色就可以理解了吧?臨近兄弟組合只能匹配第一個選擇器後面的第一個兄弟選擇其,普通兄弟組合則能匹配所有。注:該部分英文原文沒有,是神飛翻譯時自己添加。

瀏覽器支持

Internet Explorer 6依然不能理解兄弟選擇器,但是,另一種情況,如果你的用戶中只有一小部分是IE6用戶,而且網站的結構不會被破壞或者受到嚴重影響,這是實現很多很酷的效果而無需在你的HTML代碼中添加無用的classid

4. 僞類

動態僞類

之所以被稱爲動態僞類是因爲它們並不存在於HTML——而是隻有當用戶和網站交互的時候纔會呈現。

有兩類動態僞類:鏈接用戶行爲。鏈接就是:link :visited,而用戶行爲包括:hover:active :focus

在本文中提到的css選擇器中,這幾個應該是最常用到的。

:link僞類用於鏈接尚未被用戶訪問的時候,而:visited 僞類用於用戶訪問過的鏈接,也就是說它們是相反的。

:hover僞類用於用戶移動他們的鼠標在元素上,而尚未觸發或點擊它的時候。:active僞類應用於用戶點擊元素的情況。最後,:focus僞類用於元素成爲焦點的時候——最常用於表單元素。

你可以在你的樣式表中使用多種用戶行爲動態僞類,這樣你就可以,比如,根據用戶的鼠標只是滑過或懸停的時候,爲一個輸入框定義不同的背景色:

input:focus {

      background: #D2D2D2;

      border: 1px solid #5E5E5E;

      }

input:focus:hover {

      background: #C7C7C7;

      }

瀏覽器兼容性

動態僞類被所有的現代瀏覽器支持,甚至IE6,但是請注意,對於IE系列瀏覽器來說,IE6只允許:hover 僞類應用於鏈接元素(a標籤)而且只有IE8接受:active狀態。

:first-child

:first-child僞類允許你定位某個元素第一個子元素。比如,如果你想給你的無須列表的第一個li添加一個margin-top,你就可以這樣寫:

ul &gt; li:first-child {

      margin-top: 10px;

      }

讓我們來看一看另一個例子:比如你想讓你的博客的側欄的H2標籤都有個頂部邊距,以將標題和它們前面的內容區分開來,但是第一個h2不需要,你就可以使用下面的代碼:

#sidebar &gt; h2 {

      margin-top: 10px;

      }

 

#sidebar &gt; h2:first-child {

      margin-top: 0;

      }

瀏覽器兼容性

IE6 不支持 :first-child 僞類。根據僞類應用到的設計的不同,它或許不會成爲關注的主要問題。比如,如果你使用:first-child 選擇器來移除標題或段落上的頭部或底部的間距,你的佈局在IE6中不會壞掉,它只會看起來有些不同。但是如果你使用:first-child選擇器從一 個,比如浮動元素,移除左邊距或右邊距,將會讓你的設計亂掉。

語言僞類

語言僞類:lang(),允許你匹配一個基於它的語言的元素。

你如,你想讓你的網站的某個特定的鏈接根據頁面的語言有不同的背景顏色:

:lang(en) &gt; a#flag {

      background-image: url(english.gif);

      }

 

:lang(fr) &gt; a#flag {

      background-image: url(french.gif);

      }

這個選擇器將會匹配相關的鏈接——如果頁面的語言等於“en”“fr”,或者以“en”“fr”開頭並在後面帶個連字符“-”的話。

瀏覽器兼容性

不幸的是,只有IE瀏覽器中只有IE8支持該選擇器,其它的主要瀏覽器都支持該僞類選擇器。

5. CSS 3 僞類

:target

當你使用錨點(片段標識符 fragment identifier)的時候,比如,http://www.smashingmagazine.com/2009/08/02/bauhaus- ninety-years-of-inspiration/#comments,這“#comments”就是一個片段標識符,你就可以使 用:target僞類來控制目標的樣式。

舉個例子,比如你有一個很長的使用了很多文字和h2標題的頁面,然後在頁面的頭部有一個對這些標題的索引。如果在點擊索引內的某個鏈接時,相應的標題以某種方式高亮,然後滾動到相應的位置,對讀者就會很有用。很簡單。

h2:target {

      background: #F2EBD6;

      }

瀏覽器兼容性

這一次,IE瀏覽器完全不支持:target僞類,另一個小問題就是Opera 在使用前進和後退按鈕時不支持該選擇器。但是其它的各個主流瀏覽器都支持該選擇器。

UI元素狀態僞類

有些HTML元素有enable disabled 狀態(比如,文本輸入框) checked unchecked 狀態(單選按鈕和複選框)。這些狀態就可以使用:enabled:disabled :checked 僞類來分別定位。

那麼你就會想,如果任意一個禁用的(disabled)文本框應該使用淺灰色的背景和虛線邊框:

input:disabled {

      border:1px dotted #999;

      background:#F2F2F2;

      }

你也可能會想讓所有選中的複選框有個左邊距(這樣就可以在衆多的複選框中很容易認出來)

input[type=”checkbox”]:checked {

      margin-left: 15px;

      }

瀏覽器兼容性

所有的主流瀏覽器,除了我們常常不報希望的IE系列瀏覽器,都支持UI元素狀態僞類。如果你考慮只是添加附加級別的細節和增強網站的可用性,這個仍然是可以採用的。

6. CSS 3 結構僞類

:nth-child

:nth-child()僞類允許你定位某個父級元素的一個或多個特定的子元素.

你可以通過定義它的值爲一個整數來定位某個單個子元素:

ul li:nth-child(3) {

      color: red;

      }

這將會讓ul元素的第三個li元素的文字變成紅色。注意如果在ul裏面有個其它類型的元素(不是li),它也會算作其子元素。

你可以使用表達式來定位子元素。比如,下面的表達式將從第四個開始匹配每第三個元素。

ul li:nth-child(3n+4) {

      color: yellow;

      }

在上面的這個例子中,第一個黃色的li元素將會是第四個。如果也想從第一個開始匹配,你可以使用一個簡單的表達式:

ul li:nth-child(3n) {

      color: yellow;

      }

這樣的話,第一個黃色的li元素將會是第三個子元素,然後是它後面的每隔第三個。現在想象一下如果你只想匹配列表中的前四個子元素:

ul li:nth-child(-n+4) {

      color: green;

      }

:nth-child的值同樣也可以被定義爲“even” “odd”,和“2n” (第偶數個) “2n+1” (第奇數個)的效果是一樣的。

:nth-last-child

:nth-last-child僞類基本上和:nth-child僞類的作用相同,但是它從最後一個元素開始算。

使用上面的一個例子來看看:

ul li:nth-child(-n+4) {

      color: green;

      }

不是匹配最前面的四個li元素,該選擇器匹配最後面的四個元素。

你同樣可以使用“even” “odd”只,同樣與nth-child不同的是,這是從最後面的元素開始算的:

ul li:nth-last-child(odd) {

      color: grey;

      }

:nth-of-type

:nth-of-type僞類和:nth-child也很像,不同的是它只計算選擇器中指定的那個元素。

這對定位元素中包含大量不同的元素的情況會很有用。比如,我們想控制一個文本塊中的每隔一個段落,但是我們又想要無視其它元素比如圖片和引用塊:

p:nth-of-type(even) {

      color: blue;

      }

你也可以使用一些值,就像在:nth-child中使用的一樣。

:nth-last-of-type

你能猜到它吧?!:nth-last-of-type 僞類可以像前面提到的:nth-last-child一樣使用,但是這次,它將之匹配你在選擇器中指定的元素類型:

ul li:nth-last-of-type(-n+4) {

      color: green;

      }

我們可以更加的聰明一些,在一個大的塊級選擇器中結合多種這樣的僞類。比如我們想讓文章中的所有的圖片左浮動,除了第一個和最後一個(我們可以假設他們是滿寬的,無須浮動)

.post img:nth-of-type(n+2):nth-last-of-type(n+2) {

      float: left;

      }

所以在這個選擇器的第一部分,我們從第二個圖片開始定位每一個圖片。在第二部分中,我們定位所有的圖片,除了最後一個。因爲這兩個選擇器並非互斥的,我們可以同時使用它們,這樣就可以一下子排除第一個和最後一個元素!

:last-child

:last-child僞類的作用類似於:first-child 僞類,但是會定位父級元素的最後一個子元素

讓我們假設你不想讓你的日誌的div的最後一個段落也有一個底部邊距:

.post &gt; p:last-child {

      margin-bottom: 0;

      }

該選擇器將定位class”post”的元素的最後一個直接子級段落。

:first-of-type :last-of-type

:first-of-type 僞類用於定位一個父級元素下的第一個同類子元素

比如,你可以定位某個特定的div的第一個子級段落(p),並讓其第一行字母大寫:

.post &gt; p:first-of-type:first-line {

      font-variant: small-caps;

      }

在這個選擇器中,你可以確定你是在只定位class”post”的元素的直接子級p元素,而且還是匹配第一個子級p元素。

:last-of-type僞類與此類似,只是匹配最後一個子元素。

:only-child

:only-child僞類表示一個元素是它的父級元素的唯一一個子元素

比如說,你有一些盒子(“news”),裏面有一些文字段落,當你有多於一個段落的時候,你想讓文字比只有一個段落的時候小一些:

div.news &gt; p {

      font-size: 1.2em;

      }

 

div.news &gt; p:only-child {

      font-size: 1.5em;

      }

第一個選擇器中,我們定義”news”div的所有子級p元素的字體大小。在第二個中,我們覆蓋之前的字體大小,如果該p元素是“news” div的唯一子元素的時候,它的字體大小會比較大一些。

:only-of-type

:only-of-type僞類表示一個元素是它的父級元素的唯一一個相同類型的子元素

這有用什麼用?假設你有一些日誌,每一篇都有個class”post”div,他們中的一些有多於一張圖片,但是有些可能就只有一張圖片。你想讓後者中的圖片水平居中,而在其它的有多於一張圖片的日誌中,就將它左浮動。這個需求用這個選擇器就很容易實現:

.post &gt; img {

      float: left;

      }

 

.post &gt; img:only-of-type {

      float: none;

      margin: auto;

      }

:empty

:empty僞類表示一個元素裏面沒有任何內容

這個選擇器可以用很多種用途。比如,你在你的“sidebar”中有若干個盒子,但是不想讓空盒子顯示出來:

#sidebar .box:empty {

      display: none;

      }

注意,就算”box”div裏面只有一個空格,它也不會被css當作空標籤的,這樣就不能匹配該選擇器了。

瀏覽器支持

Internet Explorer (直到8.0版本)都不支持結構僞類。FirefoxSafari Opera 在其最新版本的瀏覽器中指出這些選擇器。這意味着,使用這些選擇器對網站的可用性和可訪問性是很有用的,或者如果網站的用戶中的大部分是使用IE而且你不想在某些細節上無視他們,最好還是保持使用通用的class和簡單的選擇器來迎合這些選擇器。否則你會被搞瘋的!

7. 否定選擇器

否定選擇器:not(),可以讓你定位不匹配該選擇器的元素

比如,如果你需要定義表單元素中的input元素,但是又不想包括submit類型的input的時候會灰常有用——你想它們有不同的樣式,以看起來像按鈕:

input:not([type="submit"]) {

      width: 200px;

      padding: 3px;

      border: 1px solid #000000;

      }

另一個例子,你想你的日誌的div中的所有段落(p)有比較大的字體,除了表示時間和日期的段落:

.post p:not(.date) {

      font-size: 13px;

      }

你可以想象這個選擇器能帶給你的潛力了吧,你能夠從你的CSS文件中剝離(剔除)的無用的大量選擇器也被它廣泛支持嗎?

瀏覽器支持

Internet Explorer在這裏常常是讓我們感到掃興的東西:一點都不支持,甚至在IE8中。這大概意味着這些選擇器將仍不得不等到一些開發者開始不再顧慮將它添加到他們的樣式表中才會普及。

8. 僞元素

僞元素允許你操作HTML中不是真實存在的元素,比如一個文本塊的第一行或者第一個字母。

僞元素在CSS 2.1中就已經存在,但是CSS 3說明書表示他們應該使用雙冒號“::”,以與僞類區分開來。在CSS 2.1中,他們也是使用單個冒號“:”的。瀏覽器會將能夠接受兩種格式,除非這些僞元素只存在於CSS3中。

::first-line

::first-line僞元素將匹配blockinline-blocktable-captiontable-cell等等級別元素的第一行

這對在你的文字塊上添加一些微妙的排版細節相當有用,比如,將一片文章的第一行文字改成小寫字母:

h1 + p::first-line {

      font-variant: small-caps;

      }

如果你專心的閱讀了我們前面的內容,你將會瞭解到上面的語法意味着,緊緊的跟在H1標籤之後(+)的段落會將其第一行文字顯示爲小寫字母。

你也可以針對相關的div的第一行,而不用針對實際的段落標籤(p):

div.post p::first-line { font-variant: small-caps; }

或者更進一步,定位某個特低的div的第一個段落的第一行:

div.post &gt; p:first-child::first-line {

      font-variant: small-caps;

      }

這裏,“>”符號表示你指定的是post div的直接子級元素,這樣如果段落被包括在第二級div中,它就不會匹配這個選擇器。

::first-letter

::first-letter僞元素將會匹配一個文本塊的第一個字母,除非在同一行裏面包含一些其它元素,比如圖片。

::first-line僞類一樣,::first-letter通常用於給文本元素添加排版細節,比如下沉字母或首字母。

這裏是如何使用::first-letter僞元素創建首字下沉的例子:

p {

      font-size: 12px;

      }

 

p::first-letter {

      font-size: 24px;

      float: left;

      }

注意如果你在某些元素中同時使用::first-line ::first-letter ::first-letter 屬性將覆蓋從::first-line中繼承下來的某些屬性。

如果你不知道W3C規則的話,這個元素有時會產生意想不到的結果:它事實上是使用最長的規則的選擇器!所以如果你計劃使用它的話最好仔細的閱讀一下 (其它選擇器也一樣)

::before ::after

::before::after 僞元素用於在一個元素的前面或後面插入內容,純CSS方法。

這些元素將繼承它們將附加的元素的大部分屬性。

假設你想在你的頁面中的圖標的描述前面添加文字“Graphic number x:”。你將無需寫文字“Graphic number”,或者自己手動添加數字:

.post {

      counter-reset: image;

      }

 

p.description::before {

      content: "Figure number " counter(image) ": ";

      counter-increment: image;

      }

那麼這會產生什麼?

首先,我們告訴HTML創建“image”計數器。比如我們可以添加該屬性到頁面的body。同樣我們也可以給該計數器起任何一個名字,只要你想,只要我們常常使用同樣的名字引用它:自己試試吧!

那麼我們想在class”description”的每一個段落之前添加這一塊內容: “Figure number ” — 注意只有我們在引號裏面寫的內容纔會被創建到頁面中,所以我們也要添加一個空格!

然後,我們就有了counter(image):這將用到我們之前在.post選擇器中定義的屬性。它默認會從數字1開始。

下一個屬性在那裏表示計數器知道對於每一個p.description,它需要將image計數器增加1 (counter-increment: image)

它並不像看起來的那麼複雜,而且還會灰常的有用。

::before::after僞元素常常只使用content屬性,來添加一些短語或排版元素,但是這裏我們展示了我們如果以一種更加強大的結合counter-resetcounter-increment屬性的方式來使用它們。

有趣的是: ::first-line ::first-letter 僞元素可以匹配使用::before僞元素生成的內容,如果存在的話。

瀏覽器支持

如果使用單個冒號的話(比如, :first-letter, 而不是::first-letter),這些僞元素被IE8支持(但是不被IE76支持)。但是左右其他的主流瀏覽器都支持這些選擇器。

結語

乏味的講述終於結束了,現在該你來領悟本文的要義並自己嘗試了: 開始通過創建實驗性的頁面並測試所有的這些選擇器,在有疑問的時候返回這裏並確保總是遵循W3C的規則,但是請不要只是坐在那裏想這些選擇器尚未被完全支持你就無視它們。

如果你敢於冒險,或者你不害怕放棄之前的遍地無用和非語義化的classid,爲什麼不嘗試一兩個這些強大的CSS選擇器到你的下一個項目中呢?我們保證你不會回頭的!

參考

擴展資源

關於作者

Inayaili de León 是一個葡萄牙網頁設計師。她對網頁設計和前端編碼有特別的愛好,而且喜歡漂亮和間接的網站。她居住在倫敦。你可以在Web Designer Notebook看到她的更多文章並follow her on Twitter

(轉自: http://www.qianduan.net/taming-advanced-css-selectors.html)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章