新支持的現代 CSS 偽類選擇器指南

已發表: 2022-03-10
快速總結 ↬ CSS 工作組編輯器草案第 4 級選擇器包括幾個偽類選擇器,這些選擇器已經在大多數現代瀏覽器中具有候選提案。 本指南將涵蓋目前獲得最佳支持的指南以及示例,以展示您今天如何開始使用它們!

偽類選擇器是以冒號“ : ”開頭並根據當前元素的狀態進行匹配的選擇器。 狀態可能與文檔樹相關,或者響應狀態變化,例如:hover:checked

:any-link

儘管在 Selectors Level 4 中定義,但這個偽類已經支持跨瀏覽器很長一段時間了。 any-link偽類將匹配一個錨超鏈接,只要它有一個href 。 它將以等同於同時匹配:link:visited的方式匹配。 從本質上講,如果您要添加基本屬性(例如color ),您希望將這些屬性應用於所有鏈接,而不管它們的訪問狀態如何,這可能會使您的樣式減少一個選擇器。

 :any-link { color: blue; text-underline-offset: 0.05em; }

關於特異性的一個重要注意事項是:any-link作為選擇器將勝過a ,即使a在級聯中的位置較低,因為它具有類的特異性。 在以下示例中,鏈接將為紫色:

 :any-link { color: purple; } a { color: red; }

因此,如果您引入:any-link ,請注意,如果它們將直接競爭特異性,則需要將其包含在a的實例中作為選擇器。

:focus-visible

我敢打賭,網絡上最常見的可訪問性違規之一是刪除交互元素的outline ,如鍊接、按鈕和表單輸入的:focus狀態。 該outline的主要目的之一是為主要使用鍵盤導航的用戶提供視覺指示器。 可見的焦點狀態作為一種尋路工具至關重要,因為這些用戶在界面上進行選項卡並幫助加強什麼是交互式元素。 具體來說,WCAG 成功標準 2.4.11:焦點外觀(最低)中涵蓋了可見焦點。

:focus-visible偽類旨在僅在用戶代理通過啟發式方法確定它應該可見時才顯示焦點環。 換句話說:瀏覽器將根據輸入法、元素類型和交互上下文等因素確定何時應用:focus-visible 。 出於測試目的,通過帶有鍵盤和鼠標輸入的台式計算機,您應該看到:focus-visible樣式在您進入交互式元素時附加,但在單擊它時不會看到,除了文本輸入和應該顯示:focus-visible的文本區域對所有焦點輸入類型:focus-visible

注意有關更多詳細信息,請查看:focus-visible規範的工作草案。

根據規範,最新版本的 Firefox 和 Chromium 瀏覽器現在似乎正在處理表單輸入上的:focus-visible ,該規範說,當:focus-visible匹配時,UA 應該刪除:focus樣式。 Safari 尚不支持:focus-visible ,因此我們需要確保包含:focus樣式作為後備,以避免刪除可訪問性的outline

跳躍後更多! 繼續往下看↓

給定具有以下樣式集的按鈕和文本輸入,讓我們看看會發生什麼:

 input:focus, button:focus { outline: 2px solid blue; outline-offset: 0.25em; } input:focus-visible { outline: 2px solid transparent; border-color: blue; } button:focus:not(:focus-visible) { outline: none; } button:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 2px #fff, 0 0 0 4px blue; }

鉻和火狐

  • input
    當元素通過鼠標輸入聚焦時正確刪除:focus樣式以支持:focus-visible導致更改border-color並隱藏鍵盤輸入上的outline
  • button
    不僅使用:focus-visible沒有額外的button:focus:not(:focus-visible)規則刪除:focus上的輪廓,而且只允許在鍵盤輸入上看到box-shadow

蘋果瀏覽器

  • input
    繼續僅使用:focus樣式
  • button
    現在,這似乎部分尊重了按鈕上:focus-visible的意圖,方法是在點擊時隱藏:focus樣式,但仍然在鍵盤交互時顯示:focus樣式

所以現在,建議繼續包括:focus樣式,然後逐步增強到使用演示代碼允許的:focus-visible 。 這是一個 CodePen 供您繼續測試:

請參閱 Stephanie Eckles 的 Pen [Testing application of :focus-visible](https://codepen.io/smashingmag/pen/MWJZbew)。

請參閱 Stephanie Eckles 的 :focus-visible 筆測試應用程序。

:focus-within

:focus-within偽類在所有現代瀏覽器中都有支持,並且幾乎就像父選擇器一樣,但僅適用於非常特定的條件。 當附加到包含元素並且子元素匹配:focus時,可以將樣式添加到包含元素和/或容器內的任何其他元素。

使用此行為的一個實際增強功能是在關聯輸入具有焦點時設置表單標籤的樣式。 為此,我們將標籤和輸入包裝在一個容器中,然後將:focus-within附加到該容器並選擇標籤:

 .form-group:focus-within label { color: blue; }

當輸入具有焦點時,這會導致標籤變為藍色。

此 CodePen 演示還包括直接向.form-group容器添加大綱:

請參閱 Stephanie Eckles 的 Pen [Testing application of :focus-within](https://codepen.io/smashingmag/pen/xxgmREq)。

請參閱 Stephanie Eckles 的 :focus-within 筆測試應用程序。

:is()

也稱為“匹配任何”偽類, :is()可以獲取選擇器列表來嘗試匹配。 例如,您可以將它們分組在:is(h1, h2, h3)的選擇器下,而不是單獨列出標題樣式。

關於:is()選擇器列表的一些獨特行為:

  • 如果列出的選擇器無效,則規則將繼續匹配有效的選擇器。 給定:is(-ua-invalid, article, p)規則將匹配articlep
  • 計算出的特異性將等於具有最高特異性的傳遞選擇器的特異性。 例如, :is(#id, p)將具有#id的特異性 - 1.0.0 - 而:is(p, a)將具有 0.0.1 的特異性。

忽略無效選擇器的第一個行為是一個關鍵的好處。 當在一個選擇器無效的組中使用其他選擇器時,瀏覽器將拋出整個規則。 這在一些仍然需要供應商前綴的情況下發揮作用,並且對前綴和非前綴選擇器進行分組會導致規則在所有瀏覽器中失敗。 使用:is()您可以安全地對這些樣式進行分組,它們將在匹配時應用,而在不匹配時被忽略。

對我來說,前面提到的對標題樣式進行分組已經是這個選擇器的一大勝利。 這也是我在應用非關鍵樣式時使用起來很舒服的規則類型,例如:

 :is(h1, h2, h3) { line-height: 1.2; } :is(h2, h3):not(:first-child) { margin-top: 2em; }

在這個例子中(來自我的項目 SmolCSS 中的文檔樣式),從基本樣式繼承的更大的line-height或缺少margin-top對於不支持的瀏覽器來說並不是真正的問題。 這根本不夠理想。 您暫時還不想使用:is()的是關鍵的佈局樣式,例如 Grid 或 Flex,它們可以顯著控制您的界面。

此外,當鏈接到另一個選擇器時,您可以測試基本選擇器是否與:is()中的後代選擇器匹配。 例如,以下規則僅選擇文章的直接後代段落。 通用選擇器被用作對p基本選擇器的引用。

 p:is(article > *)

為了獲得當前的最佳支持,如果您想開始使用它,您還需要通過使用:-webkit-any():matches()包含重複規則來加倍樣式。 請記住制定這些單獨的規則,否則即使支持的瀏覽器也會將其丟棄! 換句話說,包括以下所有內容:

 :matches(h1, h2, h3) { } :-webkit-any(h1, h2, h3) { } :is(h1, h2, h3) { }

在這一點上值得一提的是,與較新的選擇器本身一起是@supports的更新變體,即@supports selector 。 這也可用作@supports not selector

注意目前(現代瀏覽器),只有 Safari 不支持此規則。

您可以使用以下內容檢查:is()支持,但實際上您將失去對 Safari 的支持,因為 Safari 支持:is()但不支持@supports selector

 @supports selector(:is(h1)) { :is(h1, h2, h3) { line-height: 1.1; } }

:where()

偽類:where()幾乎與:is()相同,除了一個關鍵區別:它總是具有零特異性。 這對於正在構建框架、主題和設計系統的人們來說具有不可思議的意義。 使用:where() ,作者可以設置默認值,下游開發人員可以包括覆蓋或擴展而不會發生特異性衝突。

考慮以下一組img樣式。 使用:where() ,即使使用更高的特異性選擇器,特異性仍然為零。 在以下示例中,您認為圖像將具有哪種顏色的邊框?

 :where(article img:not(:first-child)) { border: 5px solid red; } :where(article) img { border: 5px solid green; } img { border: 5px solid orange; }

第一條規則的特異性為零,因為它完全包含在:where()中。 所以直接反對第二條規則,第二條規則獲勝。 引入img僅元素選擇器作為最後一條規則,由於級聯,它將獲勝。 這是因為它將計算與:where(article) img規則相同的特異性,因為:where()部分不會增加特異性。

由於零特異性功能,使用:where()和回退有點困難,因為該功能可能是您希望:is()上使用它的原因。 而且,如果您添加回退規則,由於其本質,這些規則可能會擊敗:where() 。 而且,它比@supports selector具有更好的整體支持,因此嘗試使用它來製作後備不太可能提供太多(如果有的話)收益。 基本上,請注意無法為:where()正確創建後備,並仔細檢查您自己的數據以確定開始為您的獨特受眾使用是否安全。

您可以使用上面使用img選擇器的以下 CodePen 進一步測試:where()

請參閱 Stephanie Eckles 的 Pen [Testing `:where()` specificity](https://codepen.io/smashingmag/pen/jOyXVMg)。

請參閱 Stephanie Eckles 的 Pen Testing :where() specificity。

增強:not()

從 Internet Explorer 9 開始支持基本的:not()選擇器。但是選擇器級別 4 通過允許它採用選擇器列表來增強:not() ,就像:is():where()一樣。

以下規則在支持瀏覽器時提供相同的結果:

 article :not(h2):not(h3):not(h4) { margin-bottom: 1.5em; } article :not(h2, h3, h4) { margin-bottom: 1.5em; }

:not()接受選擇器列表的能力具有很好的現代瀏覽器支持。

正如我們在:is()中看到的,增強的:not()還可以包含對基選擇器的引用作為使用*的後代。 這個 CodePen 通過選擇不是nav後代的鏈接來展示這種能力。

請參閱 Stephanie Eckles 的 Pen [Testing :not() with a descendent selector](https://codepen.io/smashingmag/pen/BapvQQv)。

請參閱 Stephanie Eckles 的 Pen Testing :not() 與後代選擇器。

獎勵:之前的演示還包括一個鏈接:not():is()的示例,以選擇不是h2h3元素的相鄰兄弟的圖像。

提議但“有風險”—— :has()

最後一個偽類是一個非常令人興奮的提議,但即使以實驗方式也沒有當前的瀏覽器實現它是:has() 。 事實上,它在 Selector Level 4 Editor's Draft 中被列為“有風險”,這意味著它被認為難以完成其實施,因此可能會從推薦中刪除。

如果實現, :has()本質上將是許多 CSS 人員渴望擁有的“父選擇器”。 它將使用類似於:focus-within:is()與後代選擇器的組合的邏輯,您正在尋找後代的存在,但應用的樣式將針對父元素。

給定以下規則,如果導航包含按鈕,則導航將減少頂部和底部填充:

 nav { padding: 0.75rem 0.25rem; nav:has(button) { padding-top: 0.25rem; padding-bottom: 0.25rem; }

同樣,這目前還沒有在任何瀏覽器中實現,甚至是實驗性的——但想想很有趣! Robin Rendle 在 CSS-Tricks 上為這個未來的選擇器提供了額外的見解。

3 級榮譽獎:empty

您可能在 Selectors Level 3 中錯過的一個有用的偽類是:empty ,它在元素沒有子元素(包括文本節點)時匹配該元素。

規則p:empty將匹配<p></p>但不匹配 < <p>Hello</p>

您可以使用:empty的一種方法是隱藏可能是使用 JavaScript 填充的動態內容的佔位符的元素。 也許您有一個 div 將接收搜索結果,當它被填充時,它將有一個邊框和一些填充。 但是還沒有結果,您不希望它佔用頁面上的空間。 使用:empty你可以隱藏它:

 .search-results:empty { display: none; }

您可能正在考慮在空狀態下添加一條消息,並想用偽元素和content添加它。 這裡的陷阱是輔助技術的用戶可能無法獲得消息,這些消息在他們是否可以訪問content方面是不一致的。 換句話說,為了確保可以訪問“無結果”類型的消息,您需要將其添加為像段落這樣的真實元素(隱藏的 div 將無法再訪問aria-label )。

學習選擇器的資源

CSS 有更多的選擇器,包括偽類。 這裡還有幾個地方可以了解更多關於可用內容的信息:

  • MDN CSS 選擇器文檔包括一個全面的分類列表;
  • 我已經編寫了一個由兩部分組成的高級 CSS 選擇器指南,您可以從第一部分開始;
  • 玩 CSS Diner 遊戲,愉快地學習 CSS 選擇器;
  • Kitty Giraudel 創建了一個選擇器解釋工具,它將分解和描述所提供選擇器的各個部分。