Przewodnik po nowo obsługiwanych, nowoczesnych selektorach pseudoklas CSS

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ Szkic edytora CSS Working Group Editor for Selectors Level 4 zawiera kilka pseudo-klas selektorów, które mają już kandydatów do propozycji w większości nowoczesnych przeglądarek. Ten przewodnik obejmuje te, które obecnie mają najlepsze wsparcie, wraz z przykładami, aby pokazać, jak możesz zacząć z nich korzystać już dziś!

Selektory pseudoklas to te, które zaczynają się od znaku dwukropka „ : ” i są dopasowywane na podstawie stanu bieżącego elementu. Stan może odnosić się do drzewa dokumentu lub w odpowiedzi na zmianę stanu, taką jak :hover lub :checked .

:any-link

Chociaż zdefiniowana na poziomie selektorów 4, ta pseudoklasa od dłuższego czasu obsługuje różne przeglądarki. Pseudoklasa any-link będzie pasować do hiperłącza kotwiczącego, o ile ma href . Będzie pasować w sposób równoważny równoczesnemu dopasowaniu :link i :visited . Zasadniczo może to zredukować style o jeden selektor, jeśli dodajesz podstawowe właściwości, takie jak color , który chcesz zastosować do wszystkich linków, niezależnie od ich stanu odwiedzin.

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

Ważną uwagą dotyczącą specyfiki jest to, że :any-link wygra z a jako selektor, nawet jeśli a jest umieszczone niżej w kaskadzie, ponieważ ma specyfikę klasy. W poniższym przykładzie linki będą fioletowe:

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

Jeśli więc wprowadzisz :any-link , pamiętaj, że będziesz musiał umieścić go w wystąpieniach a jako selektora, jeśli będą bezpośrednio konkurować o specyficzność.

:focus-visible

Założę się, że jednym z najczęstszych naruszeń dostępności w sieci jest usunięcie outline elementów interaktywnych, takich jak linki, przyciski i dane wejściowe formularzy dla ich stanu :focus . Jednym z głównych celów tego outline jest służenie jako wizualny wskaźnik dla użytkowników, którzy do nawigacji używają głównie klawiatur. Widoczny stan skupienia jest krytyczny jako narzędzie do znajdowania drogi, ponieważ ci użytkownicy przechodzą na zakładkę w interfejsie i pomagają wzmocnić element interaktywny. W szczególności widoczne skupienie jest ujęte w kryterium sukcesu WCAG 2.4.11: Wygląd skupienia (minimum).

Pseudoklasa :focus-visible ma na celu pokazanie pierścienia ostrości tylko wtedy, gdy klient użytkownika określi za pomocą heurystyki, że powinien być widoczny. Innymi słowy: przeglądarki określą, kiedy zastosować :focus-visible na podstawie takich rzeczy, jak metoda wprowadzania, typ elementu i kontekst interakcji. Do celów testowych za pomocą komputera stacjonarnego z klawiaturą i myszą, powinieneś zobaczyć :focus-visible style dołączone, gdy wejdziesz tabulatorem w interaktywny element, ale nie po kliknięciu go, z wyjątkiem wprowadzania tekstu i obszarów tekstowych, które powinny pokazywać :focus-visible dla wszystkich typów wprowadzania fokusa.

Uwaga : Aby uzyskać więcej informacji, przejrzyj roboczą wersję roboczą specyfikacji :focus-visible .

Wydaje się, że najnowsze wersje przeglądarek Firefox i Chromium obsługują :focus-visible na wejściach formularzy zgodnie ze specyfikacją, która mówi, że UA powinien usunąć style :focus , gdy :focus-visible pasuje. Safari nie obsługuje jeszcze :focus-visible , więc musimy upewnić się, że styl :focus jest uwzględniony jako rozwiązanie awaryjne, aby uniknąć usunięcia outline w celu ułatwienia dostępu.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Mając przycisk i tekst z następującym zestawem stylów, zobaczmy, co się stanie:

 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; }

Chromium i Firefox

  • input
    Poprawnie usuń style :focus , gdy elementy są skupione za pomocą myszy na rzecz :focus-visible co skutkuje zmianą border-color i ukryciem outline na wejściu z klawiatury
  • button
    Używa nie tylko :focus-visible bez dodatkowej reguły dla button:focus:not(:focus-visible) , która usuwa obrys na :focus , ale umożliwia widoczność box-shadow tylko na wejściu z klawiatury

Safari

  • input
    Kontynuuje używanie tylko :focus style focusów
  • button
    Wydaje się, że jest to częściowo zgodne z intencją :focus-visible na przycisku poprzez ukrycie stylów :focus po kliknięciu, ale nadal pokazywanie stylów :focus podczas interakcji z klawiaturą

Tak więc na razie zaleceniem byłoby kontynuowanie dołączania stylów :focus , a następnie stopniowe ulepszanie do używania :focus-visible , na co pozwala kod demo. Oto CodePen, za pomocą którego możesz kontynuować testowanie:

Zobacz pióro [testowanie aplikacji :focus-visible](https://codepen.io/smashingmag/pen/MWJZbew) autorstwa Stephanie Eckles.

Zobacz aplikację Pen Testing :focus-visible autorstwa Stephanie Eckles.

:focus-within

Pseudoklasa :focus-within obsługuje wszystkie nowoczesne przeglądarki i działa prawie jak selektor nadrzędny, ale tylko w bardzo określonych warunkach. Po dołączeniu do elementu zawierającego i element potomny pasuje do :focus , style mogą być dodawane do elementu zawierającego i/lub dowolnych innych elementów w kontenerze.

Praktycznym ulepszeniem korzystania z tego zachowania jest stylizacja etykiety formularza, gdy skojarzone dane wejściowe mają fokus. Aby to zadziałało, zawijamy etykietę i dane wejściowe do pojemnika, a następnie dołączamy :focus-within do tego pojemnika i wybieramy etykietę:

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

Powoduje to, że etykieta zmienia kolor na niebieski, gdy wejście ma fokus.

To demo CodePen obejmuje również dodanie konspektu bezpośrednio do kontenera .form-group :

Zobacz pióro [testowanie aplikacji :focus-within](https://codepen.io/smashingmag/pen/xxgmREq) autorstwa Stephanie Eckles.

Zobacz aplikację Pen Testing :focus-wewnątrz autorstwa Stephanie Eckles.

:is()

Znana również jako pseudoklasa „pasuje do dowolnego”, :is() może pobierać listę selektorów, z którymi próbuje się dopasować. Na przykład, zamiast wymieniać style nagłówków pojedynczo, możesz je pogrupować w selektorze :is(h1, h2, h3) .

Kilka unikalnych zachowań związanych z listą : :is() :

  • Jeśli wymieniony selektor jest nieprawidłowy, reguła nadal będzie pasować do prawidłowych selektorów. Biorąc pod uwagę :is(-ua-invalid, article, p) reguła będzie pasować do article i p .
  • Obliczona swoistość będzie równa tej z selektorem zdanym o najwyższej swoistości. Na przykład, :is(#id, p) będzie miało specyficzność #id — 1.0.0 — podczas gdy :is(p, a) będzie miało specyficzność 0.0.1.

Pierwsze zachowanie polegające na ignorowaniu nieprawidłowych selektorów jest kluczową korzyścią. Podczas korzystania z innych selektorów w grupie, w której jeden selektor jest nieprawidłowy, przeglądarka odrzuci całą regułę. Ma to znaczenie w kilku przypadkach, w których prefiksy dostawcy są nadal potrzebne, a grupowanie selektorów z prefiksem i bez prefiksu powoduje niepowodzenie reguły we wszystkich przeglądarkach. Dzięki :is() możesz bezpiecznie pogrupować te style i będą one stosowane, gdy będą pasować, i zostaną zignorowane, gdy nie będą pasować.

Dla mnie grupowanie stylów nagłówków, jak wspomniano wcześniej, jest już dużym sukcesem dzięki temu selektorowi. Jest to również rodzaj zasady, z której mógłbym korzystać bez awaryjnego rozwiązania przy stosowaniu niekrytycznych stylów, takich jak:

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

W tym przykładzie (który pochodzi ze stylów dokumentu w moim projekcie SmolCSS) posiadanie większej line-height odziedziczonej ze stylów podstawowych lub brak margin-top nie stanowi problemu dla nieobsługujących przeglądarek. To po prostu mniej niż idealne. To, czego nie chciałbyś jeszcze używać :is() , to krytyczne style układu, takie jak Grid lub Flex, które znacząco kontrolują Twój interfejs.

Dodatkowo, gdy jest powiązany z innym selektorem, możesz przetestować, czy selektor podstawowy pasuje do selektora potomnego w :is() . Na przykład poniższa reguła wybiera tylko akapity, które są bezpośrednimi potomkami przedimków. Selektor uniwersalny jest używany jako odniesienie do selektora podstawowego p .

 p:is(article > *)

Aby uzyskać najlepsze bieżące wsparcie, jeśli chcesz zacząć z niego korzystać, możesz również podwoić style , dołączając zduplikowane reguły za pomocą :-webkit-any() i :matches() . Pamiętaj, aby wprowadzić te indywidualne zasady, a nawet obsługująca je przeglądarka je wyrzuci! Innymi słowy, uwzględnij wszystkie z poniższych:

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

W tym miejscu warto wspomnieć, że wraz z samymi nowszymi selektorami jest zaktualizowana odmiana @supports , którą jest @supports selector . Jest to również dostępne jako @supports not selector .

Uwaga : obecnie (w przypadku nowoczesnych przeglądarek) tylko Safari nie obsługuje tej reguły.

Możesz sprawdzić obsługę :is() za pomocą czegoś podobnego do poniższego, ale w rzeczywistości stracisz obsługę Safari, ponieważ Safari obsługuje :is() , ale nie obsługuje @supports selector .

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

:where()

Pseudoklasa :where() jest prawie identyczna z :is() , z wyjątkiem jednej krytycznej różnicy: zawsze będzie miała zerową specyficzność. Ma to niesamowite implikacje dla osób, które tworzą frameworki, motywy i systemy projektowe . Używając :where() , autor może ustawić wartości domyślne, a dalsi programiści mogą dodawać nadpisania lub rozszerzenia bez kolidowania ze specyfiką.

Rozważ następujący zestaw stylów img . Używając :where() , nawet z selektorem o wyższej specyficzności, specyficzność pozostaje zerowa. W poniższym przykładzie, jakiego koloru obramowanie będzie miał obraz?

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

Pierwsza reguła nie jest specyficzna, ponieważ jest w całości zawarta w :where() . Tak więc bezpośrednio przeciwko drugiej regule, druga zasada wygrywa. Wprowadzając selektor tylko dla elementów img jako ostatnią zasadę, wygra dzięki kaskadzie. Dzieje się tak dlatego, że oblicza się z taką samą specyficznością jak reguła :where(article) img ponieważ część :where() nie zwiększa specyficzności.

Używanie :where() wraz z rezerwami jest nieco trudniejsze ze względu na cechę zerowej specyficzności, ponieważ ta cecha jest prawdopodobnie powodem, dla którego chciałbyś używać jej zamiast :is() . A jeśli dodasz reguły awaryjne, prawdopodobnie pokonają one :where() ze względu na swoją naturę. I ma lepsze ogólne wsparcie niż @supports selector więc próba użycia go do stworzenia awaryjnego prawdopodobnie nie zapewni dużego (jeśli w ogóle) zysku. Zasadniczo pamiętaj o niemożności prawidłowego utworzenia zastępczych funkcji dla :where() i dokładnie sprawdź własne dane, aby określić, czy można bezpiecznie zacząć używać dla unikalnych odbiorców.

Możesz dalej testować :where() za pomocą następującego CodePen, który używa powyższych selektorów img :

Zobacz specyfikację Pen [testowanie `:where()`](https://codepen.io/smashingmag/pen/jOyXVMg) Stephanie Eckles.

Zobacz specyfikę testowania pisaków :where() autorstwa Stephanie Eckles.

Ulepszone :not()

Podstawowy selektor :not() jest obsługiwany od czasów Internet Explorera 9. Ale selektory poziomu 4 ulepsza :not() , pozwalając mu na przyjęcie listy selektorów, podobnie jak :is() i :where() .

Poniższe reguły dają ten sam efekt we wspieraniu przeglądarek:

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

Zdolność :not() do zaakceptowania listy selektorów ma świetne wsparcie dla nowoczesnych przeglądarek.

Jak widzieliśmy w przypadku :is() , ulepszone :not() może również zawierać odniesienie do selektora podstawowego jako potomka za pomocą * . Ten CodePen demonstruje tę zdolność, wybierając linki, które nie są potomkami nav .

Zobacz pióro [Testowanie :not() z selektorem potomka](https://codepen.io/smashingmag/pen/BapvQQv) autorstwa Stephanie Eckles.

Zobacz testowanie pisaków :not() z selektorem potomka autorstwa Stephanie Eckles.

Bonus : Poprzednie demo zawiera również przykład łączenia :not() i :is() w celu wybrania obrazów, które nie są sąsiadującym rodzeństwem elementów h2 lub h3 .

Proponowane, ale „zagrożone” — :has()

Ostatnia pseudoklasa, która jest bardzo ekscytującą propozycją, ale nie ma żadnej przeglądarki, która by ją implementowała, nawet w sposób eksperymentalny, to :has() . W rzeczywistości jest wymieniony w wersji roboczej selektora 4 poziomu jako „zagrożony”, co oznacza, że ​​ma trudności z ukończeniem jego implementacji i dlatego może zostać usunięty z rekomendacji.

Jeśli zostanie zaimplementowana, :has() byłaby zasadniczo „selektorem nadrzędnym”, o którym wielu ludzi zajmujących się CSS chciało mieć dostęp. Działałoby to z logiką podobną do kombinacji :focus-within i :is() z selektorami potomka, gdzie szukasz obecności potomków, ale zastosowana stylizacja dotyczyłaby elementu rodzica.

Biorąc pod uwagę następującą regułę, gdyby nawigacja zawierała przycisk, nawigacja miałaby zmniejszone dopełnienie górne i dolne:

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

Ponownie, nie jest to obecnie zaimplementowane w żadnej przeglądarce, nawet eksperymentalnie — ale fajnie się nad tym zastanowić! Robin Rendle dostarczył dodatkowych informacji na temat tego przyszłego selektora na temat sztuczek CSS.

Wyróżnienie od poziomu 3: :empty

Przydatną pseudoklasą, którą mogłeś przegapić z poziomu selektorów 3, jest :empty , która dopasowuje element, gdy nie ma on elementów podrzędnych, w tym węzłów tekstowych.

Reguła p:empty będzie pasować do <p></p> , ale nie do <p>Hello</p> .

Jednym ze sposobów użycia :empty jest ukrycie elementów, które być może są miejscami zastępczymi dynamicznej zawartości wypełnionej JavaScript. Być może masz div, który otrzyma wyniki wyszukiwania, a kiedy zostanie wypełniony, będzie miał obramowanie i trochę dopełnienia. Ale jeśli nie ma jeszcze wyników, nie chcesz, aby zajmowało miejsce na stronie. Używając :empty możesz to ukryć za pomocą:

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

Być może myślisz o dodaniu wiadomości w stanie pustym i masz ochotę dodać ją z pseudoelementem i content . Pułapka polega na tym, że wiadomości mogą nie być dostępne dla użytkowników technologii wspomagających, którzy nie są spójni w kwestii dostępu do content . Innymi słowy, aby upewnić się, że komunikat typu „brak wyników” jest dostępny , możesz dodać go jako rzeczywisty element, taki jak akapit ( aria-label nie byłaby już dostępna dla ukrytego elementu div).

Zasoby do nauki o selektorach

CSS ma znacznie więcej selektorów, w tym pseudoklas. Oto kilka innych miejsc, w których można dowiedzieć się więcej o tym, co jest dostępne:

  • Dokumentacja selektorów MDN CSS zawiera obszerną, skategoryzowaną listę;
  • Napisałem dwuczęściowy przewodnik po zaawansowanych selektorach CSS, możesz zacząć od części pierwszej;
  • Baw się dobrze, poznając selektory CSS z grą CSS Diner;
  • Kitty Giraudel stworzyła narzędzie wyjaśniające selektor, które rozbija i opisuje części dostarczonego selektora.