CSS 3 所有的選擇器整理(2023.2)

Ofnoname發表於2023-02-09

你知道的和你不知道的所有選擇器。不包含尚未廣泛實現的,也不包含已棄用的。

基本的選擇器規則(Selector)

型別(Type)選擇器

直接用標籤匹配特定的元素

span {
	...
}
p {
	...
}

類(Class)選擇器

.開頭,匹配含有這個 class 的元素

.info {
	...
}
p.info { /* 匹配含有 info 類的 p 元素 */
	...
}
.info.log { /* 匹配同時含有 info 和 log 類的元素 */
	...
}

ID 選擇器

#開頭,匹配對應 id 的元素。

#info {
	...
}
p#info {
	...
}

引數(Attribute)選擇器

除了 id 和 class,也可以篩選其他引數進行匹配,並且除了全字匹配還提供了多重手段。

/* 存在 title 的 <a> 元素 */
a[title] 

/* 存在 href 屬性並且值為"https://example.org"*/
a[href="https://example.org"] 

/* 存在 href 屬性並且內容包含"example"*/
a[href*="example"] 

/* 存在 href 屬性並且以".org"結尾 */
a[href$=".org"] 

/* 存在 href 屬性並且以"https"開頭 */
a[href^="https"] 

/* class 用空格分割的列表中存在 logo。效果等於.logo。用於class這樣空格分隔的屬性 */
a[class~="logo"] 

/* 存在 lang 屬性並且以"zh"或"zh-"開頭。用於匹配lang屬性*/
div[lang|="zh"]

/* i 表示忽略大小寫 */
a[href="https://example.org" i] 

萬用字元

*表示萬用字元,可以匹配任何元素。效能較低,謹慎使用。

組合選擇器(Combinator)

組合選擇器可以連線多個元素。

子選擇器和後代選擇器

子選擇器用>表示,匹配第一個元素的直接後代的第二個元素(即 child)。後代選擇器只需要用空格隔開,不要求是直接後代(即 descendant)。

p span{ /* 所有 p 元素中的 span 元素 */
	color:red;
}
p > span{ /* 所有 p 元素中的直接子元素 span 元素 */
	color:blue;
}
<p>
	<span>p span和p>span都匹配</span>
	<p>
	  <span>只匹配p span</span>
	</p>
</p>

注意:p.info 和 p .info 是不一樣的。

兄弟選擇器和相鄰兄弟選擇器

與上文類似,兄弟選擇器用+表示,匹配第一個元素直接相鄰之後的第二個元素。相鄰兄弟選擇器用~表示,只要求是兄弟(同一個父元素),不要求相鄰。

img + p /* 緊跟在img後面的p */
img ~ p /* 和img有相同父元素的p */
<p>
	<img/>
	<p>匹配 img+p 和 img~p</p>
	<p>只匹配 img~p</p>
</p>

選擇器列表

選擇器列表用逗號,表示,用逗號連線的選擇器共同使用規則。

span, div{}
span, .info{}

注意:1. p span, .info 會匹配 p span 和 .info,而不是 p span 和 p .info,實現後者需要:is
2. 逗號選擇器是阻塞的,如果其中一個標籤不合法,整個規則都不會生效

偽類(Pseudo-Classes)

CSS 偽類是新增到選擇器的一種關鍵字,表示這個元素的特殊狀態。例如,偽類 :hover 可以用於選擇一個按鈕,當使用者的指標懸停在按鈕上時,設定此按鈕的樣式。但這個類並不真的在 class 中,所以叫偽類。偽類用:表示。

連結和按鈕相關

常用:

  • :link表示未訪問的連結,匹配尚未訪問的連結,預設一般是藍色。
  • :visited表示訪問過的連結,一般是紫色。出於隱私限制,這個偽類用的越來越少。
  • :hover表示滑鼠移向元素時的情況
  • :active表示滑鼠正在點選元素的情況
.info:link{
	color: blue;
}
.info:hover{
	color: red;
}
.info:active{
	color: purple;
}
<a href="example">a link</a>

注意: 1. 有 href 屬性的 a 標籤才是連結,沒有的不算。:link 也不只有 a 標籤,其他標籤的連結也可以(比如 link 標籤)。
2. LVHA 規則:定義同一個連結多種情況的樣式時,要按 link visited hover active 的順序。這是因為他們的優先順序相同,如果後出現的覆蓋先出現的就會出現問題,比如將 hover 放到 active 後,那點選連結時兩個偽類都滿足,hover 會覆蓋 active 導致 active 的設定不生效。

  • :any-link表示未訪問的和已訪問的連結,包括 link 和 visited。

表單輸入相關

  • :checked表示正選中的單選框(radio),核取方塊(checkbox)和下拉選單項(option)元素
  • :default表示單選框,核取方塊和下拉選單項中預設的那個元素
  • :disabled表示被禁用的元素
  • :enabled表示被啟用的元素
  • :focus表示獲得焦點的元素
  • :focus-within表示獲得焦點或者後代獲得焦點的元素
  • :focus-visible表示獲得焦點且焦點可見的元素。這是什麼意思呢?
    對於一個 input 輸入框,無論用滑鼠點選它還是用 tab 切到它,樣式都是一樣的(一般是加上一圈 outline),符合人們的習慣。
    但是對於一個 button 來說,用滑鼠點選它會觸發 :focus ,而用 tab 切換到它也會觸發 :focus(雖然沒有按下去),這就有點奇怪了。
<button> A </button>
<button> B </button>
<style> 
button:focus{ background-color: red;} /* tab 過去也生效 */
/*button:focus-visible{ background-color: green;*/}</style>

我們設定 :focus,顯然是給滑鼠按下去準備的,卻忘了鍵盤 tab 獲得焦點的情況。對於 button,用滑鼠點選的時候,你知道自己在點哪,就不算 :focus-visible;而用 tab 切換或者 js 跳轉時,你需要不一樣的焦點提醒,此時 :focus-visible 生效,這樣就可以區分二者。對於輸入框來說,所有聚焦都觸發 :focus-visible。取消掉註釋,兩種focus樣式就不再相同了。

其實瀏覽器的預設樣式就考慮到了,預設按鈕點選時會變深,tab 時則是加上一圈 outline。自己的樣式會讓預設樣式失效,如果需要精細的設計,就可以使用 :focus-visible。一個案例

  • :in-range表示值在min到max範圍內的輸入框
  • :out-of-range表示值不在min到max範圍內的輸入框
  • :indeterminate表示“不確定”的表單元素,包括設定了 indeterminate 的選框,尚未選擇的單選框,尚未完成的進度條。
  • :valid表示輸入合法的輸入框
  • :invalid表示輸入不合法的輸入框
  • :required表示設定必填的輸入
  • :optional表示設定不是必填的輸入
  • :placeholder-shown表示擁有 placeholder 的輸入框
  • :read-only表示設定了只讀屬性的輸入
  • :read-write表示可修改的輸入
  • :autofill表示按下瀏覽器自動填充功能的輸入框

DOM 子節點相關

  • :empty表示沒有子元素的元素(文位元組點也算元素,註釋不算)。比如<p>assa</p>並不能匹配,<p></p>才可以。
  • :first-child表示“是父元素的第一個子節點”。
  • :last-child表示“是父元素的最後一個子節點”。
  • :first-of-type表示“是父元素的第一個對應元素的子節點”。
  • :last-of-type表示“是父元素的最後一個對應元素的子節點”。
<p>
 <span>p :first-child 或者 span:first-child</span>
 <a>p a:first-of-type</a>
 <a></a>
</p>
  • :nth-child後接整數或一次函式,選中特性序號的孩子節點。
p :nth-child(2) /* 第二個孩子 */
p :nth-child(2n) /* 第2,4,6……個元素,n從0開始 */
p :nth-child(2n+1) /* 第1,3,5……個元素 */
p :nth-child(4n+3) /* 第4,7,10……個元素 */
p :nth-child(-n+3) /* 第3,2,1個元素 */
  • :nth-last-child同上,不過是倒著數
  • :nth-of-type同上,也就是:first-child:first-of-type的區別,限定了元素
  • :nth-last-of-type同上。
  • :only-child表示沒有其他兄弟的元素
  • :only-of-type表示沒有其他相同元素兄弟的元素

DOM 相關的其他偽類

  • :has表示“擁有……”的,它的引數是一個逗號選擇器列表。注意不能 has 巢狀。Firefox 暫不支援
p:has(span, .info)  /* 含有 span或.info的 p */
h1:has(+h2) /* 滿足h1+h2的 h1 */ 
  • :is:where後接選擇器列表,表示多選一。他們的區別是 is 計算優先順序,而 where 不計入。p :is(span, .info)表示p span 和 p .info
  • :not後接選擇器列表,和 is 相反,表示排除這些選項,選中不是這些元素的元素。
  • :root在 HTML 檔案中,:root 就等於 <html> 元素

其他

  • :modal表示“模態”,即 js 用 showModal 構造的阻塞對話方塊的樣式。一個案例
  • :lang用於選中元素的語言屬性
  • :target表示當前錨點代表的元素。比如當前 url 是example.org#title,那麼 id 為 title 的元素就會被匹配
  • :defined表示所有的預設標籤(div span)和用 js customElements.define定義的自定標籤,有了這個偽類,就可以把自定標籤定義之前和之後區分
  • :host匹配所有 shadow root 的根元素,也可以加上括號,:host()後接選擇器,表示符合條件的根元素。
  • :host-context後接選擇器,匹配在 shadow DOM 中符合條件的元素。

偽元素(Pseudo-elements)

偽元素是一個附加至選擇器末的關鍵詞,允許你對被選擇元素的特定部分修改樣式。但這個部分在 dom 中並不存在,所以叫做偽元素。用::表示,但像偽類一樣只打一個冒號也可以。

  • ::after在已選中元素之後再構造一個元素
  • ::before在已選中元素之前再構造一個元素
  • ::first-letter匹配本元素第一個字元
  • ::first-line匹配本元素第一個行
  • ::marker匹配一個 list 的元素的 marker,比如列表前面的數字序號和小圓點。
  • ::placeholder匹配輸入框的 placeholder 文字
  • ::selection表示元素中被使用者框選的部分

其他

  • ::part後接字串,匹配 shadow tree 中滿足part條件的元素
  • ::file-selector-button代表一個檔案提交按鈕
  • ::cue匹配這個元素的 WebVTT 提示
  • ::slotted匹配模板中的插槽元素
  • ::target-text匹配當前的文字錨點所在的文字。