Direct naar de inhoud

Handboek HTML5 en CSS3HTML en CSS van <a> tot z-index

Leer werken met nieuwe pseudoklassen van CSS

Het assortiment selectors van CSS is uitgebreid. Leer werken met de nieuwe pseudoklassen :is(), :where() en :not(), maak kennis met :has() en controleer je focus met :focus-within en :focus-visible.

Voor een goed begrip van dit artikel is het handig als je weet wat specificiteit is. Kan je kennis een opfrisser gebruiken, lees dan ook het artikel Specificiteit in CSS, zo werkt het.

De pseudoklassen in het kort

Behalve :has() worden alle nieuwe pseudoklassen ondersteund door de belangrijke browser.

Tussen de haakjes van :is() en :where() zet je een lijst van selectors. Elke selector die overeenkomt met een element wordt opgemaakt. Alle soorten selectors en combinators zijn toegestaan. Foute selectors worden genegeerd, maar maken niet de complete selector ongeldig. Bij :is() is de specificiteit gelijk aan de selector met de hoogste specificiteit. Bij :where() is de specificiteit altijd 0.

Ook :not() krijgt een selectorlijst. Elementen die overeenkomen met een selector in de lijst worden juist niet opgemaakt. De specificiteit is gelijk aan de selector met de hoogste specificiteit.

:has() werkt als een ‘parent selector’. De selectorlijst is een voorwaarde, geen opmaakdoel. Het is erg onzeker of :has() daadwerkelijk wordt toegevoegd aan de specificatie.

:focus-within maakt het mogelijk om een voorouder op te maken van een element dat de focus kan krijgen.

:focus-visible laat de browser bepalen of het nodig is om de focusopmaak te tonen. Wel bij toetsenbordnavigatie, niet bij muisgebruik.

Selectors bundelen met :is()

Het is geen uitzondering dat je voor verschillende elementen dezelfde basisopmaak instelt. Gewoonlijk zet je de selectors dan achter of onder elkaar met komma’s ertussen, bijvoorbeeld:

h1, h2, h3, h4 { 
  font-family: sans-serif; 
}

Met de nieuwe selector :is() schrijf je het zo:

:is(h1, h2, h3, h4) {
  font-family: sans-serif; 
}

Nee, het is niet korter. Maar het is wel foutbestendig. Maak je in de traditionele selector een fout, dan is de hele declaratie ongeldig. Deze selector bijvoorbeeld doet helemaal niks (waar zit de fout?):

h1, h2. h3, h4 {
 font-family: sans-serif; 
}

De opmaak wordt niet toegepast, ook niet op de goede onderdelen van de selector. Bij :is() wordt alleen de foute selector genegeerd. Dat is te danken aan het nieuwe CSS-waardetype ‘vergevingsgezinde selectorlijst’. Beetje lang, maar wel duidelijk. De selector werkt dus grotendeels wel, al worden nog steeds h2 en h3 overgeslagen, want de foute selector loopt van de komma na h1 tot en met de komma na h3.

See the Pen :is() by Peter Doolaard (@dool) on CodePen.

De volgende CSS-declaratie maakt een aanwijseffect op hyperlinks in de navigatie:

nav a:hover,
nav a:active {
  color: red;
  text-decoration: underline;
}

Je kunt dit ook schrijven als:

nav a:is(:active, :hover) {
    color: red;
    text-decoration: underline;
}

Dit is (iets) korter, overzichtelijk en foutbestendig. Voor de specificiteit maakt het geen verschil. Van wat bij :is() tussen haakjes staat, telt alleen de selector met de hoogste specificiteit. Hier zijn er twee pseudoklassen waarvan er dan één meetelt. De specificiteit is 012 (zie ook Specificiteit in CSS, zo werkt het).

Lagere specificiteit met :where()

Als het belangrijk is om de specificiteit laag te houden gebruik je :where(). Ook deze pseudoklasse accepteert een ‘vergevingsgezinde selectorlijst’ en voert de opmaak uit op elk overeenkomend element. In dat opzicht werkt :where() net als :is(). Er is één belangrijk verschil: :where() telt geheel niet mee voor de specificiteit. Neem als voorbeeld weer de aanwijseffecten:

nav a:where(:active, :hover) {
    color: red;
    text-decoration: underline;
}

De specificiteit van deze selector is 0,0,2. Alleen de beide typeselectors tellen mee. Daarmee is :where() een ideale selector om de specificiteit van een id te verlagen.

In het artikel over specificiteit staat het volgende voorbeeld:

#main-content article.featured h2 + p { 
  color: red; 
}

Deze selector heeft door de id een hoge specificiteit, namelijk 113. Met :where() kun je dit doen:

:where(#main-content article.featured h2 + p) {
 color: red; 
}

De specificiteit is nu 000, want zowel :where() zelf als wat tussen haakjes staat (de argumenten) telt niet mee! Dat is heel extreem, want met één elementselector overschrijf je nu die hele riedel met de id:

p {
  color: green;
}

Het ligt dan ook meer voor de hand om zoiets te doen (wat een specificiteit van 013 geeft):

:where(#main-content) article.featured h2 + p {
 color: red; 
}

See the Pen :where() by Peter Doolaard (@dool) on CodePen.

Selectors uitsluiten met :not()

Met de pseudoklasse :not() geef je uitzonderingen aan. Stel dat je alle links een aanwijseffect wilt geven, behalve die in een nav. Dan zet je wat je niet wilt meenemen tussen de haakjes van :not(). De volgende selector selecteert hyperlinks die niet afstammen van een element nav:

a:not(nav a):hover {
  background-color: black;
  color: white;
}

:not() accepteert alle soorten selectors en combinators. Dat geldt ook voor :is() en :where(). Wil je verschillende selectors gebruiken, dan zet je daar een komma tussen. Om bijvoorbeeld elke aside te selecteren die geen kop van niveau 1, 2 of 3 heeft en ook geen afbeelding, typ je:

aside:not(h1, h2, h3, img) { ... }

De specificiteit van :not() is gelijk aan de specifiekste selector tussen de haakjes. Dat is hetzelfde als bij :is().

See the Pen :not() by Peter Doolaard (@dool) on CodePen.

Idee: andersom selecteren met :has()

In CSS kun je alleen omhoog selecteren. Dat wil zeggen: je leest de selector van rechts naar links en uiteindelijk wordt het element aan de rechterkant opgemaakt. Je ziet bijvoorbeeld:

article.featured blockquote { ... }

Dan lees je (ongeveer zoals de browser ook doet):

  • selecteer elk element <blockquote>
  • dat afstamt van een klasse .featured
  • waarbij die klasse is toegepast op een <article>

Je kunt dus niet zeggen: maak elk artikel op dat een klasse .featured heeft en een <blockquote> als afstammeling. Webdevelopers willen al heel lang, heel graag zo’n ‘parent selector’ die juist dat doet. Bijvoorbeeld zo:

article.featured:has(blockquote) { ... }

Deze selector maakt het <article> op, niet de <blockquote>. De selector tussen de haakjes van :has() is een voorwaarde, geen opmaakdoel.

:has() staat in de conceptversie van CSS Selectors 4, maar het is de vraag of het verder komt dan een idee. De bedenkers van CSS voorzien problemen, bijvoorbeeld voor de prestaties van de browser. Op dit moment heb je er dus niets aan.

Pseudoklassen voor focus

Een webpagina moet volledig met een toetsenbord zijn te bedienen. Met de Tab-toets bladert een bezoeker door de elementen die focus kunnen krijgen. Dat zijn lang niet alle elementen, maar alleen elementen waarmee je iets kunt doen, zoals invullen (<input>), een link volgen (<a>) of een actie starten (<button>). Elke browser heeft ingebouwde opmaak voor de focustoestand van zulke elementen. Die kun je met CSS aanpassen, met respect voor de gouden regel: zorg ervoor dat focus altijd goed zichtbaar is.

De standaardselector voor focus is :focus. Deze gebruik je bijvoorbeeld bij een link, een invoerelement in een formulier of een knop. Zo stel je de focus van een navigatielink in:

nav a:focus {
  background-color: aqua;
}

:focus-within

:focus geldt alleen voor elementen die focus kunnen krijgen. Maar soms wil je ook een bovenliggend element focusopmaak geven, bijvoorbeeld het zoekformulier waarin het invoerveld staat. Dan selecteer je dat element met de selector :focus-within. Zodra de <input> focus krijgt, wordt de achtergrondkleur toegepast op het formulier.

See the Pen :focus-within by Peter Doolaard (@dool) on CodePen.

Gebruik je dit om een formulier met meerdere invoervelden een achtergrondkleur te geven? Let er dan op dat het invoerelement zelf ook nog steeds een duidelijke focusopmaak heeft, zodat de gebruiker ziet welk element de focus heeft.

Voor alle duidelijkheid, :focus-within werkt alleen als er een afstammeling is die daadwerkelijk focus kan krijgen.

:focus-visible

Zonder focusopmaak is je webpagina niet navigeerbaar met een toetsenbord, dus weglaten is geen optie. Toch kan focusopmaak je grafisch ontwerp in de weg zitten. Daarom is een nieuwe pseudoklasse bedacht: :focus-visible. Hiermee bepaalt de browser of het nodig is om focusopmaak te tonen. Je schrijft de CSS voor :focus-visible, maar die is niet altijd zichtbaar. Wanneer dan wel? Bijvoorbeeld als de gebruiker met het toetsenbord navigeert, als een element zonder toetsenbord niet werkt (formulierinvoer) of als de gebruiker heeft ingesteld dat hij altijd focusopmaak wil zien.

Een typisch voorbeeld is de bediening van een afbeeldingcarrousel, met hyperlinks voor de vorige en de volgende afbeelding. De bezoeker met de muis heeft geen focusopmaak nodig. Navigeert de bezoeker met de Tab-toets, dan is de focusopmaak onmisbaar. Een browser die :focus-visible niet ondersteunt valt terug naar de :focus-opmaak van de browser. Vind je dat die niet past in jouw opmaak, dan moet je zelf een regel voor :focus schrijven. Die zou de browser moeten negeren als er ook een regel voor :focus-visible is, maar dat gebeurt helaas (nog) niet. Zo wordt het gewenste effect – geen focusopmaak bij klikken – weer tenietgedaan. Zoals zo vaak bij CSS kun je dat met een slimmigheid oplossen. In de voorbeeldcode wordt dat toegelicht. (Klik op een link en gebruik daarna Tab of Shift+Tab.)

See the Pen focus-visible by Peter Doolaard (@dool) on CodePen.

De nieuwe pseudoklassen zijn terug te vinden in het concept van Selectors level 4.

Tags: css, pseudoklasse, is(), where(), not(), has(), focus, focus-within, focus-visible,


Reageer op dit artikel

* Vul a.u.b. alle velden in.