偽類與偽元素(Pseudo-classes & Pseudo-elements)
偽類描述元素的狀態或結構位置(滑鼠、焦點、第 n 個子元素)。偽元素選的是元素的某一部分,或產生額外盒子(::before)。
現代寫法:偽類一個冒號 :hover,偽元素兩個 ::before。舊網站單冒號的 :before 仍能動,新碼請用雙冒號。
狀態偽類(Pseudo-classes)
| 偽類 | 時機 |
|---|---|
:hover |
指標停在上面(觸控裝置不可靠) |
:active |
按下的瞬間 |
:focus |
獲得焦點(滑鼠點擊也會) |
:focus-visible |
瀏覽器認為需要顯示焦點時(鍵盤友善) |
:focus-within |
自己或子孫有焦點 |
:visited |
造訪過的連結(能改的屬性很少,隱私限制) |
:disabled / :enabled |
表單控件 |
:checked |
勾選的 checkbox / radio |
:required / :invalid / :valid |
表單驗證 |
:target |
URL hash 對到這個 id |
.btn:hover { background: color-mix(in srgb, var(--brand) 90%, black); }
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
input:invalid { border-color: #c62828; }
連結順序 LVFHA
若同時寫 visisted / focus / hover / active,傳統口訣是 Link Visited Focus Hover Active,避免 hover 蓋不過 visited。實務上用 class 管元件狀態更清楚。
結構偽類(Structural)
| 偽類 | 意義 |
|---|---|
:first-child / :last-child |
是父層第一 / 最後一個子節點 |
:only-child |
沒有兄弟 |
:nth-child(2n) |
第 n 個任何子元素(奇偶斑馬線) |
:nth-of-type(2) |
第 n 個同標籤 |
:first-of-type |
該標籤的第一個 |
:empty |
沒有子節點(含文字) |
:not(.hidden) |
排除 |
:is(h1, h2) / :where(...) |
分組,權重規則見 優先權 |
:has(img) |
後面符合條件的父層 |
tr:nth-child(even) { background: #fafafa; }
.field:has(:invalid) { border-color: #c62828; }
nav a:not(.is-current) { color: inherit; }
:nth-child 不是「第 n 個 p」
p:nth-child(2) 的意思是「本身是 p,且是父層的第 2 個小孩」。若第 2 個小孩是 h2,就選不到。要「第二個 p」用 p:nth-of-type(2)。
偽元素(Pseudo-elements)
| 偽元素 | 用途 |
|---|---|
::before / ::after |
在內容前後產生盒子,必須有 content(可為 "") |
::first-letter / ::first-line |
首字 / 首行 |
::selection |
滑鼠選取反白 |
::placeholder |
input 提示文字 |
::marker |
清單符號 |
::file-selector-button |
檔案上傳按鈕 |
.quote::before {
content: "「";
color: var(--brand);
}
::selection {
background: #264de4;
color: white;
}
.note::after {
content: attr(data-note);
font-size: 0.85em;
color: #666;
}
content: attr(data-note) 可把 HTML 資料屬性顯示出來,適合提示,不適合重要正文(螢幕閱讀器支援不一致)。
總結
| 偽類 | 偽元素 | |
|---|---|---|
| 選什麼 | 狀態、位置、關係 | 盒子的一部分或產生內容 |
| 寫法 | :hover |
::before |
| 例子 | :has()、:focus-visible |
::marker、::selection |