重學前端(8)CSS選擇器:偽元素是怎麼回事兒?
阿新 • • 發佈:2022-04-13
選擇器的組合
在 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 的節點。
- “||”:列選擇器,表示選中對應列中符合條件的單元格。
.c { /*......到這裡,我們就講完了如何用簡單選擇器組合成複合選擇器和複雜選擇器,形成選擇器列表,這能夠幫助我們應對各種複雜的需求。 CSS 選擇器是基於規則生效的,同一個元素命中多條規則是非常常見的事情。不同規則指定同一個屬性為不同值時,就需要一個機制來解決衝突。 選擇器的優先順序 CSS 標準用一個三元組 (a, b, c) 來構成一個複雜選擇器的優先順序。*/ } .a>.b.d { /*......*/ } 複製程式碼
- id 選擇器的數目記為 a;
- 偽類選擇器和 class 選擇器的數目記為 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
<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 中出現很多無語義的空元素。 總結 選擇器的連線方式像四則運算一樣有優先順序,
- 第一優先順序是無連線符號;
- 第二優先順序是:“空格”“~”“+”“>”“||”;
- 第三優先順序是“,”。