Un ghid pentru selectoare de pseudo-clasă CSS recent acceptate și moderne
Publicat: 2022-03-10 Selectorii de pseudoclasă sunt cei care încep cu caracterul două puncte „ :
” și se potrivesc pe baza unei stări a elementului curent. Starea poate fi relativă la arborele documentului sau ca răspuns la o schimbare de stare, cum ar fi :hover
sau :checked
.
:any-link
Deși este definită în Selectorii Nivelul 4, această pseudo-clasă are suport pentru browsere încrucișate de ceva timp. Pseudo-clasa any-link
se va potrivi cu un hyperlink ancoră atâta timp cât are un href
. Se va potrivi într-un mod echivalent cu potrivirea ambelor :link
și :visited
simultan. În esență, acest lucru vă poate reduce stilurile cu un singur selector dacă adăugați proprietăți de bază, cum ar fi color
, pe care doriți să le aplicați tuturor link-urilor, indiferent de starea lor vizitată.
:any-link { color: blue; text-underline-offset: 0.05em; }
O notă importantă despre specificitate este că :any-link
va câștiga împotriva a
ca selector, chiar dacă a
este plasat mai jos în cascadă, deoarece are specificul unei clase. În exemplul următor, linkurile vor fi violet:
:any-link { color: purple; } a { color: red; }
Deci, dacă introduceți :any-link
, fiți conștienți de faptul că va trebui să îl includeți în instanțele a
ca selector dacă vor fi în competiție directă pentru specificitate.
:focus-visible
Pariez că una dintre cele mai frecvente încălcări ale accesibilității de pe web este eliminarea outline
elementelor interactive precum linkuri, butoane și intrări de formular pentru starea lor :focus
. Unul dintre scopurile principale ale acestei outline
este de a servi drept indicator vizual pentru utilizatorii care folosesc în principal tastaturi pentru a naviga. O stare de focalizare vizibilă este esențială ca instrument de găsire a drumului, deoarece acei utilizatori filează pe o interfață și pentru a ajuta la consolidarea a ceea ce este un element interactiv. În mod specific, focalizarea vizibilă este acoperită în Criteriul de succes WCAG 2.4.11: Aspectul focalizării (minimum).
Pseudo-clasa :focus-visible
este destinată să arate un inel de focalizare numai atunci când agentul utilizator determină prin euristică că ar trebui să fie vizibil. Cu alte cuvinte: browserele vor determina când să aplice :focus-visible
pe baza unor lucruri precum metoda de introducere, tipul de element și contextul interacțiunii. În scopuri de testare prin intermediul unui computer desktop cu introducere de la tastatură și mouse, ar trebui să vedeți :focus-visible
atașate atunci când accesați un element interactiv, dar nu când faceți clic pe el, cu excepția intrărilor de text și a zonelor de text care ar trebui să arate :focus-visible
pentru toate tipurile de intrare de focalizare.
Notă : Pentru mai multe detalii, consultați schița de lucru a specificației :focus-visible
.
Cele mai recente versiuni ale browserelor Firefox și Chromium par să gestioneze acum :focus-visible
pe intrările de formular conform specificațiilor care spune că UA ar trebui să elimine stilurile : :focus
atunci când :focus-visible
potrivește. Safari nu acceptă încă :focus-visible
așa că trebuie să ne asigurăm că un stil :focus
este inclus ca rezervă pentru a evita eliminarea outline
pentru accesibilitate.
Având un buton și introducere de text cu următorul set de stiluri, să vedem ce se întâmplă:
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
Eliminați corect stilurile:focus
atunci când elementele sunt focalizate prin introducerea mouse-ului în favoarea:focus-visible
rezultând schimbareaborder-color
și ascundereaoutline
la introducerea de la tastatură -
button
Nu folosește doar:focus-visible
fără regula suplimentară pentrubutton:focus:not(:focus-visible)
care elimină conturul pe:focus
, dar va permite vizibilitateabox-shadow
numai la introducerea de la tastatură
Safari
-
input
Continuă să folosească doar stilurile:focus
-
button
Acest lucru pare să respecte parțial intenția:focus-visible
pe buton prin ascunderea stilurilor:focus
la clic, dar afișând în continuare stilurile:focus
la interacțiunea tastaturii
Deci, deocamdată, recomandarea ar fi să continuați să includeți stilurile :focus
și apoi să îmbunătățiți progresiv până la utilizarea :focus-visible
pe care o permite codul demo. Iată un CodePen cu care puteți continua testarea:
:focus-within
Pseudo-clasa :focus-within
are suport pentru toate browserele moderne și acționează aproape ca un selector părinte, dar numai pentru o condiție foarte specifică. Când sunt atașate la un element care conține și un element copil se potrivește pentru :focus
, stilurile pot fi adăugate la elementul care conține și/sau orice alte elemente din container.
O îmbunătățire practică pentru a utiliza acest comportament este stilarea unei etichete de formular atunci când intrarea asociată este focalizată. Pentru ca acest lucru să funcționeze, înfășurăm eticheta și introducem într-un container, apoi atașăm :focus-within
la acel container și selectăm eticheta:
.form-group:focus-within label { color: blue; }
Astfel, eticheta devine albastră atunci când intrarea are focalizare.
Această demonstrație CodePen include și adăugarea unui contur direct în containerul .form-group
:
:is()
Cunoscută și sub denumirea de pseudo-clasă „se potrivește cu orice”, :is()
poate lua o listă de selectori cu care să încerce să se potrivească. De exemplu, în loc să enumerați stilurile de titlu individual, le puteți grupa sub selectorul :is(h1, h2, h3)
.
Câteva comportamente unice despre lista de selecție :is()
:
- Dacă un selector listat este invalid, regula va continua să se potrivească cu selectorii validi. Având în vedere
:is(-ua-invalid, article, p)
regula se va potrivi cuarticle
șip
. - Specificitatea calculată va fi egală cu cea a selectorului trecut cu cea mai mare specificitate. De exemplu,
:is(#id, p)
va avea specificitatea#id
-ului — 1.0.0 — în timp ce:is(p, a)
va avea o specificitate de 0.0.1.
Primul comportament de ignorare a selectoarelor invalide este un avantaj cheie. Când utilizați alți selectoare într-un grup în care un selector este invalid, browserul va elimina întreaga regulă. Acest lucru intră în joc pentru câteva cazuri în care prefixele furnizorului sunt încă necesare, iar gruparea selectoarelor prefixate și fără prefix face ca regula să eșueze între toate browserele. Cu :is()
puteți grupa în siguranță acele stiluri și se vor aplica atunci când se potrivesc și vor fi ignorate atunci când nu se potrivesc.
Pentru mine, gruparea stilurilor de titlu așa cum am menționat anterior este deja un mare câștig cu acest selector. Este, de asemenea, tipul de regulă pe care m-aș simți confortabil să o folosesc fără o rezervă atunci când aplic stiluri non-critice, cum ar fi:
:is(h1, h2, h3) { line-height: 1.2; } :is(h2, h3):not(:first-child) { margin-top: 2em; }
În acest exemplu (care provine din stilurile de document din proiectul meu SmolCSS), a avea o line-height
moștenită de la stilurile de bază sau lipsa margin-top
nu este cu adevărat o problemă pentru browserele care nu acceptă. Este pur și simplu mai puțin decât ideal. Ceea ce nu ați dori încă să utilizați :is()
ar fi stiluri de aspect critice, cum ar fi Grid sau Flex, care vă controlează în mod semnificativ interfața.
În plus, atunci când este conectat la un alt selector, puteți testa dacă selectorul de bază se potrivește cu un selector descendent din :is()
. De exemplu, următoarea regulă selectează numai paragrafele care sunt descendenți direcți ai articolelor. Selectorul universal este folosit ca referință la selectorul de bază p
.
p:is(article > *)
Pentru cel mai bun suport actual, dacă doriți să începeți să-l utilizați, veți dori, de asemenea, să dublați stilurile , incluzând reguli duplicate folosind :-webkit-any()
și :matches()
. Amintiți-vă să faceți aceste reguli individuale, sau chiar browserul de suport îl va arunca! Cu alte cuvinte, includeți toate următoarele:
:matches(h1, h2, h3) { } :-webkit-any(h1, h2, h3) { } :is(h1, h2, h3) { }
Merită menționat în acest moment că, împreună cu selectoarele mai noi în sine, există o variantă actualizată a @supports
care este @supports selector
. Acesta este disponibil și ca @supports not selector
.
Notă : În prezent (dintre browserele moderne), doar Safari nu acceptă această regulă at.
Ai putea verifica suportul pentru :is()
cu ceva de genul următor, dar de fapt ai pierde suportul pentru Safari, deoarece Safari acceptă :is()
dar nu acceptă @supports selector
.
@supports selector(:is(h1)) { :is(h1, h2, h3) { line-height: 1.1; } }
:where()
Pseudo-clasa :where()
este aproape identică cu :is()
cu excepția unei diferențe critice: va avea întotdeauna specificitate zero. Acest lucru are implicații incredibile pentru cei care construiesc cadre, teme și sisteme de proiectare . Folosind :where()
, un autor poate seta valorile implicite, iar dezvoltatorii din aval pot include suprascrieri sau extensii fără a se confrunta cu specificul.
Luați în considerare următorul set de stiluri img
. Folosind :where()
, chiar și cu un selector de specificitate mai mare, specificitatea rămâne zero. În exemplul următor, ce chenar de culoare crezi că va avea imaginea?
:where(article img:not(:first-child)) { border: 5px solid red; } :where(article) img { border: 5px solid green; } img { border: 5px solid orange; }
Prima regulă are nicio specificitate, deoarece este cuprinsă în întregime în :where()
. Deci direct împotriva celei de-a doua reguli, a doua regulă câștigă. Introducând selectorul numai pentru elemente img
ca ultimă regulă, va câștiga datorită cascadei. Acest lucru se datorează faptului că va calcula la aceeași specificitate ca și regula :where(article) img
, deoarece porțiunea :where()
nu crește specificitatea.
Utilizarea :where()
alături de alternative este puțin mai dificilă din cauza caracteristicii de zero specificitate, deoarece această caracteristică este probabil motivul pentru care ați dori să o utilizați peste :is()
. Și dacă adăugați reguli de rezervă, acestea sunt susceptibile de a învinge :where()
datorită însăși naturii sale. Și are un suport general mai bun decât @supports selector
așa că încercarea de a-l folosi pentru a crea o soluție de rezervă nu este probabil să ofere mult (dacă există) un câștig. Practic, fiți conștienți de incapacitatea de a crea corect alternative pentru :where()
și verificați cu atenție propriile date pentru a determina dacă este sigur să începeți să utilizați pentru publicul dvs. unic.
Puteți testa în continuare :where()
cu următorul CodePen care utilizează selectoarele img
de mai sus:
Îmbunătățit :not()
Selectorul de bază :not()
a fost acceptat începând cu Internet Explorer 9. Dar Selectorii Nivelul 4 îmbunătățește :not()
permițându-i să ia o listă de selectoare, la fel ca :is()
și :where()
.
Următoarele reguli oferă același rezultat în compatibilitatea browserelor:
article :not(h2):not(h3):not(h4) { margin-bottom: 1.5em; } article :not(h2, h3, h4) { margin-bottom: 1.5em; }
Capacitatea lui :not()
de a accepta o listă de selecție are un suport excelent pentru browser-ul modern.
După cum am văzut cu :is()
, enhanced :not()
poate conține și o referință la selectorul de bază ca descendent folosind *
. Acest CodePen demonstrează această capacitate selectând link-uri care nu sunt descendenți ai nav
.
Bonus : demonstrația anterioară include, de asemenea, un exemplu de înlănțuire a :not()
și :is()
pentru a selecta imagini care nu sunt frați adiacente fie ale elementelor h2
, fie ale h3
.
Propus, dar „în pericol” — :has()
Pseudo-clasa finală care este o propunere foarte interesantă, dar nu are niciun browser actual care să o implementeze chiar și într-un mod experimental este :has()
. De fapt, este listat în Proiectul Editorului Selector Nivelul 4 ca fiind „la risc”, ceea ce înseamnă că este recunoscut că are dificultăți în finalizarea implementării sale și, prin urmare, poate fi eliminat din recomandare.
Dacă este implementat, :has()
ar fi în esență „selectorul părinte” pe care mulți oameni CSS și-au dorit să îl aibă disponibil. Ar funcționa cu o logică similară cu o combinație a ambelor :focus-within
și :is()
cu selectori descendenți, unde căutați prezența descendenților , dar stilul aplicat ar fi elementului părinte.
Având în vedere următoarea regulă, dacă navigarea conținea un buton, atunci navigarea ar fi scăzut umplutura de sus și de jos:
nav { padding: 0.75rem 0.25rem; nav:has(button) { padding-top: 0.25rem; padding-bottom: 0.25rem; }
Din nou, acest lucru nu este implementat în prezent în niciun browser, nici măcar experimental - dar este distractiv de gândit! Robin Rendle a oferit informații suplimentare despre acest viitor selector pe CSS-Tricks.
Mențiune de Onoare de la Nivelul 3: :empty
O pseudo-clasă utilă pe care s-ar putea să o fi ratat de la Selectors Level 3 este :empty
care se potrivește cu un element atunci când nu are elemente copil, inclusiv noduri de text.
Regula p:empty
se va potrivi cu <p></p>
, dar nu cu <p>Hello</p>
.
O modalitate prin care puteți utiliza :empty
este să ascundeți elementele care sunt probabil substituenți pentru conținutul dinamic care este populat cu JavaScript. Poate că aveți un div care va primi rezultate ale căutării și, atunci când este populat, va avea o chenar și o umplutură. Dar fără rezultate încă, nu doriți să ocupe spațiu pe pagină. Folosind :empty
îl puteți ascunde cu:
.search-results:empty { display: none; }
S-ar putea să vă gândiți să adăugați un mesaj în starea goală și să fiți tentat să îl adăugați cu un pseudo-element și content
. Capcanul aici este că este posibil ca mesajele să nu fie disponibile pentru utilizatorii tehnologiei de asistență, care sunt inconsistente cu privire la posibilitatea de a accesa content
. Cu alte cuvinte, pentru a vă asigura că un mesaj de tip „fără rezultate” este accesibil , ați dori să adăugați că un element real, cum ar fi un paragraf (o aria-label
nu ar mai fi accesibilă pentru un div ascuns).
Resurse pentru a afla despre selectori
CSS are mult mai mulți selectori, inclusiv pseudo-clase. Iată câteva locuri pentru a afla mai multe despre ceea ce este disponibil:
- Documentația MDN CSS selectoare include o listă cuprinzătoare clasificată;
- Am scris un ghid în două părți pentru selectoarele CSS avansate, puteți începe cu partea întâi;
- Distrează-te învățând despre selectoarele CSS cu jocul CSS Diner;
- Kitty Giraudel a creat un instrument de explicație a selectorului care va descompune și va descrie părți ale unui selector furnizat.