iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Modern Web

前端迷走中:從零開始的新手之路系列 第 21

[Day 21] 選擇不障礙,讓CSS幫你──偽類選擇器 上

  • 分享至 

  • xImage
  •  

昨天我們講解了對任何屬性都能使用的屬性選擇器。

今天要繼續來介紹偽類選擇器。

關於偽類

偽類選擇器(Pseudo-Class),也可以譯作虛擬類別選擇器。由字面上來看,是一種依據實際上不存在的類別來挑選內容的選擇器。

這些偽類,可以理解成系統依據某些標準,默默對每個元素做的分類。就像是現實世界的人、生物或物品等,可以依據各種標準來分類一樣。

由於偽類不是我們基於分類需求,自己幫元素添加的類別(class屬性值),所以說它們是不存在的類別。

有了這些現成的偽類,就不需要再添加class屬性值做重複的分類。而且這些偽類會隨著元素狀態的變化動態調整,也可以省去手動修改屬性值的麻煩。

基本語法

我們可以使用類別選擇器,依據元素的class屬性值來挑選內容;
同樣的,我們也可以使用偽類選擇器,依據元素的偽類來挑選內容。

在CSS中,以:name()的語法表示偽類選擇器。
偽類名稱以冒號:開頭,名稱與冒號間不能有空格;
函式型偽類選擇器在名稱後面會多加上括號,名稱與括號間同樣不能有空格。

偽類名稱跟CSS所有的關鍵字一樣,都不區分大小寫。但還是建議都用小寫,比較有一致性。

組成複合選擇器

偽類選擇器跟元素選擇器、類別選擇器、ID選擇器、通用選擇器跟屬性選擇器一樣,都屬於簡單選擇器(simple selector)。[^1]

簡單選擇器可以彼此相接組成之前提過的複合選擇器。
但偽類選擇器只能接在元素選擇器或通用選擇器後面。

如果要指定是對哪一種元素做篩選,就在冒號前面加上元素選擇器,例如element:name()
如果沒有加上元素選擇器,就意味著是對所有種類的元素都做篩選,等同於冒號前面加上通用選擇器*:name(),只是把通用選擇器省略掉。

偽類選擇器彼此也可以相接在一起組成複合選擇器。但有些偽類彼此的意義是互斥的,如果加在一起就篩選不出任何東西。

分類

依據規範的定義,可以將這些偽類選擇器大致分成兩種:[^1]

Pseudo-classes are simple selectors that permit selection based on information that lies outside of the document tree or that can be awkward or impossible to express using the other simple selectors.

一種是基於文件檔案以外的資訊將元素分類與篩選(這裡先將document tree理解為文件檔案);
另一種,則是基於文件檔案本身提供的資訊將元素分類與篩選,而這種篩選難以或無法透過其他的簡單選擇器來達成。

基於上述差異可以將這些偽類選擇器進一步細分。不過Selectors Level 3跟Selectors Level 4的分類方式不同。

這裡參考Selectors Level 3的分類方式,將偽類選擇器分成六種類型:[^2]

  • 動態偽類(Dynamic pseudo-classes)
    包括:link:visited等連結偽類;
    :hover:active:focus等使用者操作偽類。

  • 目標偽類(The target pseudo-class)
    :target

  • 語言偽類(The language pseudo-class)
    :lang

  • UI元素狀態偽類(The UI element states pseudo-classes)
    包括:enabled:disabled
    :checked:indeterminate等。

  • 結構偽類(Structural pseudo-classes)
    包括:root:empty
    :first-child:last-child:first-of-type:last-of-type
    :nth-child():nth-last-child():nth-of-type():nth-last-of-type()
    :only-child:only-of-type等。

  • 否定偽類 The negation pseudo-class
    :not

以下先介紹動態偽類。

動態偽類

動態偽類是依據元素名稱、屬性與內容以外,無法由文件檔案本身得到的資訊,做出的分類。

像是可以從檔案知道網頁中有什麼連結,但無法知道其中哪些連結已經點過,哪些沒有點過。還需要另外比對瀏覽記錄,才能知道每個連結的訪問狀態。

連結偽類

連結偽類(the link pseudo-classes)是依連結訪問狀態做出的分類。總共分成兩種互斥的狀態:

  • :link,表示連結沒有訪問過。
  • :visited,表示連結已經訪問過。

區分連結的訪問狀態並設定不同的樣式對使用者很有幫助。如果網頁中太多連結,使用者可能會忘記哪些連結還沒點過。

不過這麼做也有資安疑慮。如果掌握使用者訪問過哪些網站,可能會危及言論自由,也可能有被釣魚或詐騙的疑慮。

為免有心人士搭配腳本找出訪問過的網站,:visited受到限制,只能用於設定顏色相關的樣式;
所有透過:link設定的樣式,也會一併套用到已經訪問過的連結;
透過DOM查詢已訪問連結的樣式,會得到與未訪問連結相同的結果。[^3]

注意事項

  • <a>元素新增的內容,需要有href屬性才會被視作連結。
  • 經過一段時間之後,瀏覽器可能將訪問過的連結變回未訪問的狀態。

使用者操作偽類

使用者操作偽類(the user action pseudo-classes)將元素依使用者操作狀態分成三種狀態:

  • :hover
    使用者目前以指標設備指向的元素。
    通常會是滑鼠指標目前所在的元素。
    使用其他設備可能無法偵測這種狀態,像是觸控裝置、筆。
  • :active
    使用者目前正在觸發的元素。
    通常會是滑鼠指標目前點擊,還未鬆開的元素。
  • :focus
    使用者以滑鼠、鍵盤或其他輸入裝置操作後,目前擁有焦點的元素。
    通常會是滑鼠最近一次點擊,或是以鍵盤tab鍵移動到的元素。

:active:hover是一瞬間的狀態,:focus則是延續性的狀態。[^4]
如果是以滑鼠操作,這三種狀態會分別出現在以下時機:

  • 點擊變成:active:focus狀態前,需要先:hover
  • 點擊當下,會同時處在:active:focus:hover的狀態。
  • 點擊完成後,:focus的狀態會延續,直到點選其他地方。
  • 點擊完成後,滑鼠指標還未移走前,會處在:hover的狀態。

由於這三種狀態沒有互斥,可能同時存在多個狀態。所以可以接在一起組成複合選擇器,像是a:focus:hover

使用者操作偽類通常會用於連結。但也可能用於表單等其他元素。

注意事項

不是每個元素都能變成:active:focus的狀態,這取決於文件使用的標記語言,以及瀏覽器的實作。[^2]

由於三種狀態沒有互斥,在使用偽類選擇器宣告同種屬性的樣式時需要注意順序,不然有些樣式可能會被蓋掉:[^4]
把點擊後會延續的:focus放在最前面;
接著放滑鼠指標離開前會一直觸發的:hover
最後放滑鼠點擊當下才會觸發的:active

連結偽類與使用者操作偽類的搭配使用

由於使用者操作偽類常常用於連結,如果同時以連結偽類設定同種屬性的樣式時也需要注意順序,以免樣式被蓋掉。[^3]

連結偽類是持久性的狀態,應該放在以使用者操作偽類設定的規則之前;
:link:visited是互斥的狀態,彼此之間不會互相影響,順序不重要;
使用者操作偽類之間的先後順序,如同前述是:focus:hover:active

於是組合起來就會是:link:visited:focus:hover:active(被稱為LVFHA原則),
或是:visited:link:focus:hover:active

小結

今天我們先介紹了什麼是偽類,還有偽類的基本語法。

可以將偽類理解為一種依據元素當下狀況自動添加、動態調整的分類。類似於class的用途,但不需要我們自己設定屬性。

在進行這樣的分類時,除了參考檔案本身,也會參考文件檔案以外的資訊。因此可依分類依據的資訊來源將偽類做區分。

今天最後介紹的動態偽類,就是參考文件檔案以外的資訊所做的分類。

包括描述連結是否已點擊訪問的:link:visited等連結偽類;
描述使用者操作狀態的:focus:hover:active等使用者操作偽類。

至於其他偽類,因為時間差不多了,就下集待續吧~

參考

[^1]: W3C, Selectors Level 4
[^2]: W3C, Selectors Level 3
[^3]: CSS大全,第四版。
[^4]: 黯羽轻扬, 超链接的lvha原则


上一篇
[Day 20] 選擇不障礙,讓CSS幫你──屬性選擇器
系列文
前端迷走中:從零開始的新手之路21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言