CSS selectors 選擇器
選擇器的基本意義是:根據一些特征,選中元素樹上的一批元素。
-
總覽分類
- 簡單選擇器:針對某一特征判斷是否選中元素。
- 復合選擇器:連續寫在一起的簡單選擇器,針對元素自身特征選擇單個元素。
- 復雜選擇器:由“(空格)”“ >”“ ~”“ +”“ ||”等符號連接的復合選擇器,根據父元素或者前序元素檢查單個元素。
- 選擇器列表:由逗號分隔的復雜選擇器,表示“或”的關系
-
詳解
-
簡單選擇器
-
類型選擇器和全體選擇器
-
類型選擇器有 div span p html body a 這些,選中的是全部的DOM 上的元素。
-
全體選擇器就是 *,選中全部的元素。我們通常用來覆蓋默認樣式、寫字體格式這些。
-
-
id 選擇器與 class 選擇器
- # 選中 id
- . 選中 class
這里有個值得一提的是,document.getElementBy...的性能要比 document.querySelector...的性能好的多,盡量用document.getElementBy
-
屬性選擇器
-
[att]
只要元素有這個屬性,不論屬性是什么值,都可以被選中。
-
[att=val]
精確匹配,檢查一個元素屬性的值是否是 val。
-
[att~=val]
多種匹配,檢查一個元素的值是否是若干值之一,這里的 val 不是一個單一的值了,可以是用空格分隔的一個序列。
-
[att|=val]
開頭匹配,檢查一個元素的值是否是以 val 開頭,它跟精確匹配的區別是屬性只要以 val 開頭即可,后面內容不管。
這個設計有點不符合直覺,感覺^=更靠譜點,畢竟正則是這么寫的。。。
-
-
偽類選擇器
-
樹結構關系偽類選擇器
- :empty 偽類表示沒有子節點的元素,這里有個例外就是子節點為空白文本節點的情況。
- :nth-child 和 :nth-last-child 這是兩個函數型的偽類,CSS 的 An+B 語法設計的是比較復雜的,我們這里僅僅介紹基本用法。我們還是看幾個例子:
-
:nth-last-child 的區別僅僅是從后往前數。
-
:first-child :last-child 分別表示第一個和最后一個元素。
-
:only-child 按字面意思理解即可,選中唯一一個子元素。
-
of-type 系列,是一個變形的語法糖,S:nth-of-type(An+B) 是:nth-child(|An+B| of S) 的另一種寫法。以此類推,還有 nth-last-of-type、first-of-type、last-of-type、only-of-type。
-
鏈接與行為偽類選擇器(常用的一批)
- :any-link 表示任意的鏈接,包括 a、area 和 link 標簽都可能匹配到這個偽類
- :link 表示未訪問過的鏈接, :visited 表示已經訪問過的鏈接。
- :hover 表示鼠標懸停在上的元素。
- :active 表示用戶正在激活這個元素,如用戶按下按鈕,鼠標還未抬起時,這個按鈕就處於激活狀態。
- :focus 表示焦點落在這個元素之上。
- :target 用於選中瀏覽器 URL 的 hash 部分所指示的元素。
- 在 Selector Level 4 草案中,還引入了 target-within、focus-within 等偽類,用於表示 target 或者 focus 的父容器。具體可以去看看 w3c selector 4
-
邏輯偽類選擇器
-
:not 偽類。
*|*:not(:hover)
-
-
其他的偽類選擇器(了解即可)
dir、lang、play、pause、current、past、future、nth-col、nth-last-col
-
-
復合選擇器
連續寫在一起 如:
html body div span .interesting #666selector { background-color: 'azure'; }
-
復雜選擇器
-
選擇器的組合
- “空格”:后代,表示選中所有符合條件的后代節點, 例如“ .a .b ”表示選中所有具有 class 為 a 的后代節點中 class 為 b 的節點。
- “>” :子代,表示選中符合條件的子節點,例如“ .a>.b ”表示:選中所有“具有 class 為 a 的子節點中,class 為 b 的節點”。
- “~” : 后繼,表示選中所有符合條件的后繼節點,后繼節點即跟當前節點具有同一個父元素,並出現在它之后的節點,例如“ .a~.b ”表示選中所有具有 class 為 a 的后繼中,class 為 b 的節點。
這么理解更簡單,前面有.a 的 所有 .b元素
- “+”:直接后繼,表示選中符合條件的直接后繼節點,直接后繼節點即 nextSlibling。例如 “.a+.b ”表示選中所有具有 class 為 a 的下一個 class 為 b 的節點。
- “||”:列選擇器,表示選中對應列中符合條件的單元格。
我們在實際使用時,比較常用的連接方式是“空格”和“>”。
工程實踐中一般會采用設置合理的 class 的方式,來避免過於復雜的選擇器結構,這樣更有利於維護和性能。空格和子代選擇器通常用於組件化場景,當組件是獨立開發時,很難完全避免 class 重名的情況,如果為組件的最外層容器元素設置一個特別的 class 名,生成 CSS 規則時,則全部使用后代或者子代選擇器,這樣可以有效避免 CSS 規則的命名污染問題。
-
選擇器的優先級
-
優先級順序
- 第一優先級
- 無連接符號
- 第二優先級
- “空格”
- “~”
- “+”
- “>”
- “||”
- 第三優先級
- “,”
- 第一優先級
-
優先級計算
CSS 標准用一個三元組 (a, b, c) 來構成一個復雜選擇器的優先級。
-
id 選擇器的數目記為 a;
-
偽類選擇器和 class 選擇器的數目記為 b;
-
偽元素選擇器和標簽選擇器數目記為 c;
-
“*” 不影響優先級。
-
行內屬性的優先級永遠高於 CSS 規則,瀏覽器提供了一個“口子”,就是在選擇器前加上“!import”。這個用法非常危險,因為它相當於一個新的優先級,而且此優先級會高於行內屬性
CSS 標准建議用一個足夠大的進制,獲取“ a-b-c ”來表示選擇器優先級。
specificity = base * base * a + base * b + c
base 是一個“足夠大”的正整數。關於 base,歷史中有些趣聞,早年 IE6 采用 256 進制,於是就產生“256 個 class 優先級等於一個 id”這樣的奇葩問題,后來擴大到 65536,基本避免了類似的問題。
我們這么計算,specificity = a * 100 + b * 10 + c * 1
同一優先級的選擇器遵循“后面覆蓋前面的原則”。
實際寫代碼的時候還是少來點選擇器,不然代碼可讀性會受到影響,不利於維護。(會被打死。。。)
-
-
-
-
選擇器列表
就是一個 “,” 逗號,表示 或者 的關系。。。
-
-
-
偽元素
這個東西還沒說呢
目前兼容性達到可用的偽元素有以下幾種。
- ::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>
p::first-line { text-transform: uppercase }
這一段代碼把段落的第一行字母變為大寫。注意這里的第一行指的是排版后顯示的第一行,跟 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 lines will 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>
div>p#a { color:green; } div::first-line { color:blue; }
這段代碼最終結果第一行是藍色,因為 p 是塊級元素,所以偽元素出現在塊級元素之內,所以內層的 color 覆蓋了外層的 color 屬性。
如果我們把 p 換成 span,結果就是相反的。
<div> <span id=a>First paragraph</span><br/> <span>Second paragraph</span> </div>
div>span#a { color:green; } div::first-line { color:blue; }
這段代碼的最終結果是綠色,這說明偽元素在 span 之外。
::first-letter 的行為又有所不同,它的位置在所有標簽之內,我們把前面的代碼換成::first-letter。
<div> <span id=a>First paragraph</span><br/> <span>Second paragraph</span> </div>
div>span#a { color:green; } div::first-letter { color:blue; }
執行這段代碼,我們可以看到,首字母變成了藍色,這說明偽元素出現在 span 之內。
CSS 標准只要求 ::first-line 和 ::first-letter 實現有限的幾個 CSS 屬性,都是文本相關,這些屬性是下面這些。
-
說說 ::before 和 ::after 偽元素
這兩個偽元素跟前面兩個不同的是,它不是把已有的內容套上一個元素,而是真正的無中生有,造出一個元素。
::before 表示在元素內容之前插入一個虛擬的元素,::after 則表示在元素內容之后插入。
這兩個偽元素所在的 CSS 規則必須指定 content 屬性才會生效,我們看下例子:
<p class="special">I'm real element</p>
p.special::before { display: block; content: "pseudo! "; }
這里要注意一點,::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 中出現很多無語義的空元素。