Przewodnik po nowo obsługiwanych, nowoczesnych selektorach pseudoklas CSS
Opublikowany: 2022-03-10 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.
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 ukryciemoutline
na wejściu z klawiatury -
button
Używa nie tylko:focus-visible
bez dodatkowej reguły dlabutton: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:
: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
:
: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ć doarticle
ip
. - 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
:
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
.
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.