虛擬類別

CSS Podcast - 015:虛擬類別

假設您有一個電子郵件註冊表單,且希望電子郵件表單欄位在含有無效電子郵件地址時顯示紅色邊框。該怎麼做?您可以使用 :invalid CSS 虛擬類別,這是瀏覽器提供的眾多虛擬類別之一。

偽類別可讓您根據狀態變更和外部因素套用樣式。 也就是說,設計可以回應使用者輸入的內容,例如無效的電子郵件地址。 這些內容會在選取器單元中說明,本單元則會詳細介紹。

與虛擬元素不同 (詳情請參閱上一個單元),虛擬類別會連結至元素可能處於的特定狀態,而不是一般樣式元素的部分。

互動狀態

使用者與網頁互動時,會套用下列虛擬類別。

:hover

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

Source

如果使用者有滑鼠或觸控板等指標裝置, 並將指標放在元素上, 您可以使用 :hover 勾住該狀態,套用樣式。 這項屬性可提示元素可供互動。

:active

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

當使用者與元素互動 (例如點選) 時,系統會觸發這個狀態,直到放開點選為止。如果使用滑鼠等指標裝置,這個狀態是指點選開始但尚未放開。

:focus:focus-within:focus-visible

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

如果元素可以接收焦點 (例如 <button>),您可以使用 :focus 虛擬類別對該狀態做出反應。

如果元素的子項元素收到焦點,您也可以使用 :focus-within 做出反應。

可聚焦的元素 (例如按鈕) 聚焦時會顯示焦點環,即使點選也是如此。在這種情況下,開發人員會套用下列 CSS:

button:focus {     outline: none; } 

當元素收到焦點時,這項 CSS 會移除預設的瀏覽器焦點環,這會對使用鍵盤瀏覽網頁的使用者造成無障礙問題。如果沒有焦點樣式,使用者就無法在使用 Tab 鍵時追蹤目前的焦點位置。使用 :focus-visible,您可以在元素透過鍵盤取得焦點時呈現焦點樣式,同時使用 outline: none 規則,在指標裝置與元素互動時防止呈現焦點樣式。

button:focus {     outline: none; }  button:focus-visible {     outline: 1px solid black; } 

:target

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.3.

Source

:target 虛擬類別會選取具有與網址片段相符的 id 元素。 假設您有下列 HTML:

<article id="content">     <!-- ... --> </article> 

如果網址包含 #content,您可以將樣式附加至該元素。

#content:target {     background: yellow; } 

這項功能有助於醒目顯示可能已特別連結的區域,例如使用跳轉連結的網站主要內容。

歷史狀態

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

:link 虛擬類別可套用至任何具有href 值,但尚未造訪的 <a> 元素。

:visited

您可以使用 :visited 虛擬類別,為使用者已造訪的連結設定樣式。這與 :link 的狀態相反,但基於安全考量,您可使用的 CSS 屬性較少。您只能為 colorbackground-colorborder-coloroutline-color 和 SVG fillstroke 的顏色設定樣式。

順序很重要

如果您定義 :visited 樣式,至少具有相同特異性的連結虛擬類別可以覆寫該樣式。因此,建議您使用 LVHA 規則,依特定順序為含有虛擬類別的連結設定樣式::link:visited:hover:active

a:link {} a:visited {} a:hover {} a:active {} 

表單狀態

下列虛擬類別可選取表單元素,以及這些元素在互動期間可能處於的各種狀態。

:disabled:enabled

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

如果瀏覽器停用表單元素 (例如 <button>),您可以使用 :disabled 虛擬類別掛鉤至該狀態。:enabled 虛擬類別適用於相反狀態,但表單元素預設也是 :enabled,因此您可能不會使用這個虛擬類別。

:checked:indeterminate

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

當支援的表單元素 (例如核取方塊或圓形按鈕) 處於勾選狀態時,即可使用 :checked 虛擬類別。

:checked 狀態是二進位 (true 或 false) 狀態,但核取方塊在勾選或取消勾選時,確實有中間狀態。這就是所謂的 :indeterminate 狀態。

舉例來說,如果您有「全選」控制項,可勾選群組中的所有核取方塊,就會出現這種狀態。如果使用者隨後清除其中一個核取方塊,根核取方塊就不再代表「全部」已勾選,因此應處於不確定狀態。

<progress> 元素也有不確定狀態,可設定樣式。 常見的用途是顯示條紋外觀,表示還需要多少資源尚不清楚。

:placeholder-shown

Browser Support

  • Chrome: 47.
  • Edge: 79.
  • Firefox: 51.
  • Safari: 9.

Source

如果表單欄位有 placeholder 屬性,但沒有值,則可以使用 :placeholder-shown 虛擬類別,將樣式附加至該狀態。只要欄位中有內容,無論是否含有 placeholder,這個狀態就不會再適用。

驗證狀態

Browser Support

  • Chrome: 10.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 5.

Source

您可以使用 :valid:invalid:in-range 等虛擬類別,回應 HTML 表單驗證。 :valid:invalid 虛擬類別適用於電子郵件欄位等情境,這類欄位必須有相符的 pattern,才能成為有效欄位。這個有效值狀態會顯示給使用者,協助他們瞭解可以安全地移至下一個欄位。

如果輸入內容有 minmax,例如數值輸入 值位於這些界限內,則可以使用 :in-range 虛擬類別。

使用 HTML 表單時,您可以透過 required 屬性判斷欄位是否為必填。:required 虛擬類別適用於必填欄位。您可以使用 :optional 虛擬類別選取非必填欄位。

依索引、順序和出現次數選取元素

有一組虛擬類別會根據項目在文件中的位置選取項目。

:first-child:last-child

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 3.
  • Safari: 3.1.

Source

如要尋找第一個或最後一個項目,可以使用 :first-child:last-child。這些虛擬類別會傳回同層級元素群組中的第一個或最後一個元素。

:only-child

Browser Support

  • Chrome: 2.
  • Edge: 12.
  • Firefox: 1.5.
  • Safari: 3.1.

Source

您也可以使用 :only-child 虛擬類別,選取沒有同層級的元素。

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

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

您可以選取 :first-of-type:last-of-type,這兩個標記一開始看起來與 :first-child:last-child 相同,但請考慮以下 HTML:

<div class="my-parent">     <p>A paragraph</p>     <div>A div</div>     <div>Another div</div> </div> 

以及這個 CSS:

.my-parent div:first-child {     color: red; } 

由於第一個子項是段落,而非 div,因此不會有任何元素標示為紅色。:first-of-type 虛擬類別在這個情況下很有用。

.my-parent div:first-of-type {     color: red; } 

即使第一個 <div> 是第二個子項,但仍是 .my-parent 元素內的第一個型別,因此會套用這項規則,並顯示為紅色。

:nth-child:nth-of-type

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

您也可以使用其他子項和型別。 :nth-child:nth-of-type 虛擬類別可讓您指定位於特定索引的元素。CSS 選取器中的索引從 1 開始。

:nth-last-child():nth-last-of-type() 虛擬類別會從結尾開始計算,而非開頭。

您也可以將索引以外的項目傳遞至這些虛擬類別。 如要選取所有偶數元素,可以使用 :nth-child(even)

您也可以使用 An+B 微語法,建立更複雜的選取器,以固定間隔尋找項目。

li:nth-child(3n+3) {     background: yellow; } 

這個選取器會選取每三個項目中的一個, 從第 3 個項目開始。這個運算式中的 n 是索引,從零開始,而 3 (3n) 則是索引的乘數。

假設您有 7 個 <li> 項目。 選取的第一個項目是 3,因為 3n+3 會轉譯為 (3 * 0) + 3。 下一次疊代會挑選項目 6,因為 n 現在已遞增為 1, 因此 (3 * 1) + 3)。 這個運算式適用於 :nth-child:nth-of-type

:nth-child():nth-last-child() 也支援「of S」語法,可讓您使用選取器篩選比對項目,類似於 :nth-of-type()li:nth-of-type(even) 相當於 :nth-child(even of li):nth-of-type 只允許您依據元素類型 (例如 lip) 篩選,但「of S」語法允許您依據任何選取器篩選。

如果表格很長,建議在每隔一列的位置加上條紋,雖然您可以使用 tr:nth-child(even) 指定每隔一個資料列,但如果篩除部分資料列,這個方法就無法運作。如果您透過套用 hidden 屬性來實作篩選功能,可以在選取器中加入 of :not([hidden]),預先篩除隱藏項目,再選取偶數列。

tr:nth-child(even of :not([hidden])){   background: lightgrey; } 

您可以在這個 nth-child 測試工具或這個數量選取器工具上,試用這類選取器。

:only-of-type

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

最後,您可以在同層級元素群組中,找出特定類型的唯一元素: :only-of-type。 如果您想選取只有一個項目的清單,或是想找出段落中唯一加粗的元素,這項功能就非常實用。

尋找空白元素

有時識別完全空白的元素可能很有用,而這也有對應的虛擬類別。

:empty

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

如果元素沒有子項,則適用 :empty 虛擬類別。不過,子項不只是 HTML 元素或文字節點,也可能是空白字元,因此在偵錯下列 HTML 時,如果想知道為何無法搭配 :empty 使用,可能會感到困惑:

<div> </div> 

原因是開頭和結尾 <div> 之間有空白字元,因此 :empty 無法運作。

如果您對 HTML 的控制權較少,且想要隱藏空白元素 (例如 WYSIWYG 內容編輯器),:empty 虛擬類別就非常實用。這裡的編輯者新增了空白段落。

<article class="post">  <p>Donec ullamcorper nulla non metus auctor fringilla.</p>  <p></p>  <p>Curabitur blandit tempus porttitor.</p> </article> 

你可以使用 :empty 找出並隱藏該內容。

.post :empty {     display: none; } 

尋找及排除多個元素

部分虛擬類別可協助您編寫更精簡的 CSS。

:is()

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: 78.
  • Safari: 14.

Source

如要找出 .post 元素中的所有 h2liimg 子項元素,您可能會想編寫如下的選取器清單:

.post h2, .post li, .post img {      } 

使用 :is() 虛擬類別,可以編寫更精簡的版本:

.post :is(h2, li, img) {     /* ... */ } 

:is 虛擬類別不僅比選取器清單更精簡,也更寬容。 在大多數情況下,如果選取器清單中含有錯誤或不支援的選取器,整個選取器清單就會失效。如果 :is 虛擬類別中傳遞的選取器有誤,系統會忽略無效的選取器,但會使用有效的選取器。

:not()

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

您也可以使用 :not() 虛擬類別排除項目。舉例來說,您可以使用這項功能,為沒有 class 屬性的所有連結設定樣式。

a:not([class]) {     color: blue; } 

:not 偽類別也有助於提升無障礙功能。 舉例來說,<img> 必須有 alt,即使是空值也一樣,因此您可以編寫 CSS 規則,為無效圖片新增粗紅色的外框:

img:not([alt]) {     outline: 10px red; } 

:has()

如果想根據元素內含的內容設定樣式,該怎麼做?您可以使用 :has() 虛擬類別來執行這項操作。舉例來說,您可能想為包含圖示的按鈕套用樣式。

 button:has(svg) {   /* ... */ } 

在最基本的設定中 (如上一個範例所示),您可以將 :has() 視為父項選取器。您也可以搭配其他選取器使用相符的父項選取器,指定其他元素。

form:has(input:valid) label {   font-weight: bold; }  form:has(input:valid) label::after {   content: "✅"; } 

在這個範例中,當表單輸入含有 valid 虛擬類別時,我們會將樣式套用至標籤元素和 label::after 虛擬元素。

:has() 虛擬類別無法巢狀內嵌在另一個 :has() 中,但可以與其他虛擬類別合併使用。

:is(h1, h2, h3):has(a) {    /* ... */ } 

選取器清單不容有誤,因此如果清單中有任何選取器無效,系統就會忽略所有樣式規則。

.my-element:has(img, ::before) {   /* any styles here will be discarded since pseudo elements can't be included in the :has() selector list */ } 

隨堂測驗

測試您對虛擬類別的瞭解

虛擬類別的作用就像是動態套用至元素的類別,而虛擬元素則會作用於元素本身。

請注意,選取器中是否使用單一或雙 : 做為鍵的區別字元
虛擬元素適用於部分,虛擬類別適用於狀態。

下列哪些是函式虛擬類別?

:is()
🎉
:target
功能性虛擬類別後面會加上 (),表示接受參數。
:empty
功能性虛擬類別後面會加上 (),表示接受參數。
:not()
🎉

下列哪些虛擬類別是由使用者互動所致?

:hover
🎉
:press
請再試一次!
:squeeze
請再試一次!
:target
🎉
:focus-within
🎉

下列哪些是 <form> 狀態虛擬類別?

:enabled
🎉
:fresh
請再試一次!
:indeterminate
🎉
:checked
🎉
:in-range
🎉
:loading
請再試一次!
:valid
🎉