1. 程式人生 > 其它 >重學前端(8)CSS選擇器:偽元素是怎麼回事兒?

重學前端(8)CSS選擇器:偽元素是怎麼回事兒?

選擇器的組合   在 CSS 規則中,選擇器部分是一個選擇器列表。   選擇器列表是用逗號分隔的複雜選擇器序列;複雜選擇器則是用空格、大於號、波浪線等符號連線的複合選擇器;複合選擇器則是連寫的簡單選擇器組合。根據選擇器列表的語法,選擇器的連線方式可以理解為像四則運算一樣有優先順序。 第一優先順序:無連線符號   複合選擇器表示簡單選擇器中“且”的關係,例如,例子中的“ .b.d ”,表示選中的元素必須同時具有 b 和 d 兩個 class。 複雜選擇器是針對節點關係的選擇,它規定了五種連線符號。
  • “空格”:後代,表示選中所有符合條件的後代節點, 例如“.a .b ”表示選中所有具有 class 為 a 的後代節點中 class 為 b 的節點。
  • “>” :子代,表示選中符合條件的子節點,例如“.a>.b ”表示:選中所有“具有 class 為 a 的子節點中,class 為 b 的節點”。
  • “~” : 後繼,表示選中所有符合條件的後繼節點,後繼節點即跟當前節點具有同一個父元素,並出現在它之後的節點,例如“.a~.b ”表示選中所有具有 class為 a 的後繼中,class 為 b 的節點。
  • “+”:直接後繼,表示選中符合條件的直接後繼節點,直接後繼節點即 nextSlibling。例如 “.a+.b ”表示選中所有具有 class 為 a 的下一個 class 為 b 的節點。
  • “||”:列選擇器,表示選中對應列中符合條件的單元格。
我們在實際使用時,比較常用的連線方式是“空格”和“>”。   工程實踐中一般會採用設定合理的 class 的方式,來避免過於複雜的選擇器結構,這樣更有利於維護和效能。   空格和子代選擇器通常用於元件化場景,當元件是獨立開發時,很難完全避免 class 重名的情況,如果為元件的最外層容器元素設定一個特別的 class 名,生成 CSS規則時,則全部使用後代或者子代選擇器,這樣可以有效避免 CSS 規則的命名汙染問題。   逗號表示“或”的關係,實際上,可以把它理解為“兩條內容一樣的 CSS 規則”的一種簡寫。如我們開頭的例子,可以理解成與下面的程式碼等效:
.c {
/*......
*/ } .a>.b.d { /*......*/ } 複製程式碼
  到這裡,我們就講完了如何用簡單選擇器組合成複合選擇器和複雜選擇器,形成選擇器列表,這能夠幫助我們應對各種複雜的需求。 CSS 選擇器是基於規則生效的,同一個元素命中多條規則是非常常見的事情。不同規則指定同一個屬性為不同值時,就需要一個機制來解決衝突。   選擇器的優先順序 CSS 標準用一個三元組 (a, b, c) 來構成一個複雜選擇器的優先順序。
  • id 選擇器的數目記為 a;
  • 偽類選擇器和 class 選擇器的數目記為 b;
  • 偽元素選擇器和標籤選擇器數目記為 c;
  • “*” 不影響優先順序。
CSS 標準建議用一個足夠大的進位制,獲取“ a-b-c ”來表示選擇器優先順序。 即:
specificity = base * base * a + base * b + c
其中,base 是一個“足夠大”的正整數。關於 base,歷史中有些趣聞,早年 IE6 採用 256 進位制,於是就產生“256 個 class 優先順序等於一個 id”這樣的奇葩問題,後來擴大到 65536,基本避免了類似的問題。     現代瀏覽器多采用了更大的數量,我們正常編寫的 CSS 規則數量不太可能達到數萬,因此我們可以認為這樣的 base 就足夠大了。   行內屬性的優先順序永遠高於 CSS 規則,瀏覽器提供了一個“口子”,就是在選擇器前加上“!import”。   這個用法非常危險,因為它相當於一個新的優先順序,而且此優先順序會高於行內屬性。   同一優先順序的選擇器遵循“後面的覆蓋前面的”原則,我們可以看一個例子:
<div id="my" class="x y">text<div>

.x {
background-color:lightblue;
}
.y {
background-color:lightgreen;
}

 

調換“.x”和“.y”我們可以得到不同的顯示效果。選擇器的優先順序是針對單條規則的,多條規則的選擇器同時命中元素,優先順序不會發生疊加。
<div id="my" class="x y z">text<div>

.x {
background-color:lightblue;
}
.z {
background-color:lightblue;
}
.y {
background-color:lightgreen;
}
在這個例子中,“.x ”和“.z ”都指定了背景色為淺藍色,但是因為“.y ”規則在最後,所以最終顯示結果為淺綠色。另外一個需要注意的是,選擇器的優先順序是針 對複雜選擇器的優先順序,選擇器列表不會合並計算優先順序。 我們看一個例子:
<div id="my" class="x y z">text<div>

.x, .z {
background-color:lightblue;}
.y {
background-color:lightgreen;
}
這裡選擇器列表“   .x, .z”命中了 div,但是它的兩項分別計算優先順序,所以最終優先順序仍跟“.y” 規則相同。   以上就是選擇器優先順序的相關規則了,雖然我們這裡介紹了詳細的計算方式,但是我認為選擇器的使用上,如果產生複雜的優先順序計算,程式碼的可讀性一定是有問題的。   所以實踐中,建議你“根據 id 選單個元素”“class 和 class 的組合選成組元素”“tag 選擇器確定頁面風格”這樣的簡單原則來使用選擇器,不要搞出過於複雜的選擇器。   偽元素   偽元素本身不單單是一種選擇規則,它還是一種機制。   偽元素的語法跟偽類相似,但是實際產生的效果卻是把不存在的元素硬選出來。 目前相容性達到可用的偽元素有以下幾種。
  • ::first-line
  • ::first-letter
  • ::before
  • ::after
下面我們就來分別講講它們。   ::first-line 和 ::first-letter 是比較類似的偽元素,其中一個表示元素的第一行,一個表示元素的第一個字母。 我們可以看一個示例:
<p>This is a somewhat long HTML
paragraph that will be broken into several
lines. The first line will be identified
by a fictional tag sequence. The other lines
will be treated as ordinary lines in the
paragraph.</p>
這一段程式碼把段落的第一行字母變為大寫。注意這裡的第一行指的是排版後顯示的第一行,跟 HTML 程式碼中的換行無關。 ::first-letter 則指第一個字母。首字母變大並向左浮動是一個非常常見的排版方式。
<p>This is a somewhat long HTML
paragraph that will be broken into several
lines. The first line will be identified
by a fictional tag sequence. The other lineswill be treated as ordinary lines in the
paragraph.</p>


p::first-letter {
text-transform: uppercase;
font-size:2em;
float:left;
}

 

雖然聽上去很簡單,但是實際上,我們遇到的 HTML 結構要更為複雜,一旦元素中不是純文字,規則就變得複雜了。 CSS 標準規定了 first-line 必須出現在最內層的塊級元素之內。因此,我們考慮以下程式碼。
<div>
<p id=a>First paragraph</p>
<p>Second paragraph</p>
</div>

 

這段程式碼最終結果第一行是藍色,因為 p 是塊級元素,所以偽元素出現在塊級元素之內,所以內層的 color 覆蓋了外層的 color 屬性。如果我們把 p 換成 span,結果就是相反的。
<div>
<span id=a>First paragraph</span><br/>
<span>Second paragraph</span>
</div>

 

這段程式碼的最終結果是綠色,這說明偽元素在 span 之外。 ::first-letter 的行為又有所不同,它的位置在所有標籤之內,我們把前面的程式碼換成::first-letter。
<div>
<span id=a>First paragraph</span><br/>
<span>Second paragraph</span>
</div>

 

執行這段程式碼,我們可以看到,首字母變成了藍色,這說明偽元素出現在 span 之內。 CSS 標準只要求 ::first-line 和 ::first-letter 實現有限的幾個 CSS 屬性,都是文字相關,這些屬性是下面這些。

 

 

接下來我們說說 ::before 和 ::after 偽元素。   這兩個偽元素跟前面兩個不同的是,它不是把已有的內容套上一個元素,而是真正的無中生有,造出一個元素。   ::before 表示在元素內容之前插入一個虛擬的元素,::after 則表示在元素內容之後插入。   這兩個偽元素所在的 CSS 規則必須指定 content 屬性才會生效,我們看下例子:
<p class="special">I'm real element</p>


這裡要注意一點,::before 和 ::after 還支援 content 為 counter,如:

<p class="special">I'm real element</p>
p.special::before {
display: block; content: counter(chapno, upper-roman) ". ";
}
這對於實現一些列表樣式是非常有用的。 ::before 和 ::after 中支援所有的 CSS 屬性。實際開發中,這兩個偽元素非常有用,有了這兩個偽元素,一些修飾性元素,可以使用純粹的 CSS 程式碼新增進去,這能 夠很好地保持 HTML 程式碼中的語義,既完成了顯示效果,又不會讓 DOM 中出現很多無語義的空元素。   總結 選擇器的連線方式像四則運算一樣有優先順序,
  • 第一優先順序是無連線符號;
  • 第二優先順序是:“空格”“~”“+”“>”“||”;
  • 第三優先順序是“,”。
  然後我們又介紹了選擇器優先順序的計算方式。 最後我們為大家介紹了偽元素,我們逐次講解了 ::first-line ::first-letter ::before ::after 四種偽元素。 偽元素的語法跟偽類相似,但是實際產生的效果是把不存在的元素硬選出來這一點就與偽類不太一樣了。