Un ghid pentru selectoare de pseudo-clasă CSS recent acceptate și moderne

Publicat: 2022-03-10
Rezumat rapid ↬ Schița editorului pentru grupul de lucru CSS pentru selectori Nivelul 4 include mai multe selectoare pseudo-clase care au deja candidați pentru propuneri în majoritatea browserelor moderne. Acest ghid le va acoperi pe cele care au în prezent cel mai bun suport, împreună cu exemple pentru a demonstra cum puteți începe să le utilizați astăzi!

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.

Mai multe după săritură! Continuați să citiți mai jos ↓

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 schimbarea border-color și ascunderea outline la introducerea de la tastatură
  • button
    Nu folosește doar :focus-visible fără regula suplimentară pentru button:focus:not(:focus-visible) care elimină conturul pe :focus , dar va permite vizibilitatea box-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:

Vedeți Pen [Testarea aplicației :focus-visible](https://codepen.io/smashingmag/pen/MWJZbew) de Stephanie Eckles.

Vezi aplicația de testare a stiloului pentru :focus-visible de Stephanie Eckles.

: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 :

Vedeți Pen [Testarea aplicației :focus-within](https://codepen.io/smashingmag/pen/xxgmREq) de Stephanie Eckles.

Vezi aplicația de testare a stiloului :focus-within de Stephanie Eckles.

: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 cu article și p .
  • 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:

Vedeți Pen [Testing `:where()` specificity](https://codepen.io/smashingmag/pen/jOyXVMg) de Stephanie Eckles.

Vezi specificul Testing Pen :where() de Stephanie Eckles.

Î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 .

Vedeți Pen [Testarea :not() cu un selector descendent](https://codepen.io/smashingmag/pen/BapvQQv) de Stephanie Eckles.

Vedeți Testarea stiloului :not() cu un selector descendent de Stephanie Eckles.

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.