Zichtbare focus en focusindicatoren

Je tabt door een formulier. Na drie keer op Tab drukken weet je niet meer waar je bent. Er is geen rand, geen kleurverandering, geen enkel teken dat een element focus heeft. Zonder focusindicator is het lastig navigeren.

In dit artikel leg ik uit hoe een focusindicator werkt, waarom die zichtbaar moet zijn en hoe je zorgt dat hij ook echt te zien is.

Wat is een focusindicator?

Een focusindicator is een visuele markering. Die laat bij toetsenbordnavigatie zien welk element op dit moment de focus heeft. Doorgaans is dat een zichtbare rand rondom het element.

Focusindicator

De focus kan op verschillende manieren worden weergegeven. Dit zijn de meest voorkomende manieren:

  • Rand of omlijning: Een zichtbare rand verschijnt rond het element.
  • Onderstreping: Een dikke lijn wordt toegevoegd onder of naast het element.
  • Kleurverandering: Een duidelijke verandering van tekst of achtergrond van het element.
  • Toegevoegde iconen: Een symbool, zoals een pijl, verschijnt naast een element.
  • Vetgedrukte of onderstreepte tekst: Tekst wordt opvallend en afwijkend opgemaakt.
  • Caret: De verticale streep die in een leeg invoerveld verschijnt (of de tekst wordt geselecteerd).

Iedereen die niet met een muis werkt, is afhankelijk van de focusindicator. Denk aan mensen die met het toetsenbord navigeren. Maar ook aan mensen met een motorische beperking die een alternatieve toetsenbordinterface gebruiken, zoals een eenknopsschakelaar of een zuig-/blaasschakelaar (sip-and-puff).

Code van een focusindicator

Maak een focusindicator op met de CSS-pseudoklasse :focus. Deze pseudoklasse past stijl toe op een element als het de toetsenbordfocus krijgt.

Een basisvoorbeeld voor een link:

​a:focus {
  outline: 3px solid #005a9c; 
  outline-offset: 2px;
} ​

Dit zorgt er voor dat er een focusrand verschijnt als iemand met Tab naar de link navigeert. Dit werkt voor elk bedieningselement dat focus kan krijgen, zoals <a>, <button> en <input>.

:focus en :focus-visible

Alleen :focus opmaken heeft een (klein) nadeel: de focusindicator verschijnt dan ook als iemand met de muis op de link klikt, dus niet alleen bij toetsenbordgebruik. Voor muisgebruikers is die focusrand eigenlijk overbodig.

De oplossing is de CSS-pseudoklasse :focus-visible. Browsers maken met :focus en :focus-visible onderscheid tussen de twee situaties:

  • :focus is altijd actief als een element focus heeft. Het maakt niet uit of dat via het toetsenbord, de muis of een script gebeurt.
  • :focus-visible is alleen actief als de browser bepaalt dat een focusindicator nuttig zou zijn. In de praktijk betekent dat: bij toetsenbordnavigatie wél, maar bij muisklikken niet.

Een werkbaar patroon voor bijna elke codebase:

/* Focusstijl voor toetsenbordgebruikers */
:focus-visible {
  outline: 3px solid #005a9c;
  outline-offset: 2px;
}

/* Verberg de outline bij muisgebruik, maar alleen als :focus-visible beschikbaar is */
:focus:not(:focus-visible) {
  outline: none;
}

Focus moet zichtbaar zijn

Succescriterium 2.4.7 Focus zichtbaar heeft één eis: alle bedieningselementen die met het toetsenbord bediend kunnen worden, moeten een zichtbare indicator van de toetsenbordfocus hebben.

Goed nieuws: alle grote browsers tonen standaard al een zichtbare focusindicator. Tab je door een pagina zonder eigen CSS, dan zie je vanzelf een rand rond de links, knoppen en invoervelden. Maar mét eigen CSS verdwijnt die standaard focusindicator nog regelmatig. Bijvoorbeeld door een algemene CSS-reset of door eigen CSS met outline: none of outline: 0 zonder dat er iets voor terugkomt.

De browserstandaard is niet altijd duidelijk

Leun niet alleen op de standaardstijl van de browser. Een blauwe focusring op een blauwe achtergrond valt nauwelijks op. Hetzelfde geldt voor een lichtgrijze rand op een witte achtergrond. Definieer daarom bij voorkeur een eigen :focus– of :focus-visible-stijl.

De focusindicator heeft voldoende contrast nodig

Zichtbaar is niet hetzelfde als goed zichtbaar. Succescriterium 2.4.7 Focus zichtbaar vraagt alleen dát er een indicator is. Hoe goed die moet opvallen, daar zorgt succescriterium 1.4.11 Contrast van niet-tekstuele content voor. Een focusstijl die je zelf opmaakt, moet minstens 3:1 contrast hebben met de aangrenzende kleur.

Welke kleur precies “aangrenzend” is, hangt af van de plek van de indicator. Een rand buiten het element vergelijk je met de achtergrond van de pagina, niet met het element zelf. Een indicator binnen het element vergelijk je met de achtergrondkleur van het element. Ligt de indicator deels binnen en deels buiten? Dan is één deel met genoeg contrast voldoende.

Hoe je contrast meet (ook bij kleurverlopen, afbeeldingen en transparantie), en welke contrasteisen gelden voor andere toestanden (zoals hover en aangevinkt), dat lees je in het artikel Kleurcontrast op je website.

Info

Op niveau AA stelt WCAG geen eis aan de dikte of grootte van je focusindicator. Een dunne rand van 1 pixel met genoeg contrast voldoet dus, ook al is die lastig te zien. WCAG 2.2 heeft wel een AAA-criterium dat hier eisen aan stelt: succescriterium 2.4.13 Focusweergave. Een gebied van de indicator moet dan minstens zo groot zijn als een omtrek van 2 CSS-pixels dik rond de niet-gefocuste component. En datzelfde gebied moet een contrastverhouding van minstens 3:1 hebben tussen de gefocuste en de niet-gefocuste toestand. Maakt de auteur de focusindicator niet zelf op, dan geldt het criterium niet.

Het gefocuste element mag niet worden bedekt

Succescriterium 2.4.11 Focus niet bedekt (minimum) eist: als een bedieningselement de focus heeft, dan mag dat element niet volledig verborgen worden achter andere content.

Dit criterium kijkt naar het moment dat een element de focus krijgt. Is het element op dat moment volledig bedekt, dan is dat een fout. Verschijnt er daarna content overheen, dan valt dat buiten dit criterium.

Wanneer gaat het mis?

Stel je hebt een header die bovenaan de pagina “plakt” (position: sticky). Je gebruiker navigeert met Shift + Tab terug door de pagina. Op een gegeven moment krijgt een link in het midden van de pagina de focus. Die link verdwijnt precies onder de sticky header. Het element heeft focus, maar is volledig verborgen.

Hetzelfde patroon doet zich voor bij:

  • een sticky footer of cookiebanner onderaan de pagina die een bedieningselement bedekt bij het tabben
  • een uitklapmenu dat openblijft en onderliggende elementen bedekt
  • een pop-up die zichzelf over de content zet zonder focus op te eisen

Modale dialoogvensters vallen hier niet onder. Zo’n venster krijgt de focus bij het verschijnen en houdt die vast tot het sluit. Het element met focus is dan het venster zelf, en dat is zichtbaar. Pakt het venster de focus niet en kun je erachter tabben? Dan kan het alsnog falen.

Wat “volledig bedekt” betekent

Het criterium zegt: niet volledig bedekt. Is een deel van het element nog zichtbaar, ook al is het maar een klein beetje? Dan is er geen fout.

Een halftransparante laag over je content is een apart geval. Het element blijft erdoorheen zichtbaar, dus bedekt is het niet. Maar zo’n laag verlaagt wel het contrast van de focusindicator. Zakt dat onder de 3:1 uit de vorige sectie? Dan is dat alsnog een fout, maar dan op het contrast.

Let op

De rand van alleen de focusindicator telt niet als “nog zichtbaar”. Zit de knop volledig achter de cookiebanner en steekt alleen de outline eruit? Dan is dat toch een fout. Dit werkt anders bij een indicator bínnen het element, of bij focus via een kleurverandering van het element zelf. Die telt wél mee als zichtbaar deel.

Andersom kan ook: het element is nog deels zichtbaar, maar de indicator zelf is volledig bedekt. Het element is dan niet volledig bedekt, dus hier gaat het niet mis. Maar dat is wel weer een fout onder succescriterium 2.4.7 Focus zichtbaar.

Info

WCAG 2.2 heeft ook een AAA-versie van dit criterium: succescriterium 2.4.12 Focus niet bedekt (uitgebreid). Voor dat criterium geldt: geen enkel deel van het gefocuste element mag bedekt zijn.

Uitzonderingen

Er zijn twee uitzonderingen:

  1. Content die de gebruiker zelf heeft verplaatst: als iemand zwevende content kan verslepen, dan telt alleen de beginpositie.
  2. Content die de gebruiker zelf heeft geopend: als iemand zelf een popover opent en daarna naar een element tabt dat daardoor bedekt raakt, is dat geen fout. Voorwaarde is dat de gebruiker het element zichtbaar kan maken zonder de focus te verplaatsen, bijvoorbeeld door Escape in te drukken.

Deze uitzonderingen gelden alleen voor content die de gebruiker zelf actief verplaatst of opent. Content die je als ontwerper of ontwikkelaar zelf hebt geplaatst, valt er nooit onder. Dat geldt ook voor content die vanzelf verschijnt, zoals een automatische melding of waarschuwing.

De oplossing: scroll-padding en twee alternatieven

De meest robuuste oplossing is de CSS-eigenschap scroll-padding. Daarmee reserveer je ruimte, zodat de browser een gefocust element niet achter je sticky header, footer of banner scrolt. Heb je een sticky header van 80 pixels? Reserveer dan minstens die hoogte, plus een kleine buffer.

Een voorbeeld met een sticky header van 80 px en een sticky cookiebanner van 60 px:

:root {
  --header-hoogte: 80px;
  --banner-hoogte: 60px;
}

html {
  padding-bottom: var(--banner-hoogte);
  scroll-padding-top: calc(var(--header-hoogte) + 8px);
  scroll-padding-bottom: calc(var(--banner-hoogte) + 8px);
}

De + 8px geeft een kleine buffer. Zo komt het element niet precies aan de rand van de sticky content terecht. De padding-bottom is nodig voor elementen helemaal onderaan de pagina, zoals links in de footer. Zonder die extra ruimte kan de browser deze elementen niet boven de banner scrollen, want voorbij het einde van de pagina scrollen kan niet.

Scroll-padding werkt alleen voor content aan de rand van het scherm, zoals een sticky header of footer. Bedekt een chatwidget of niet-modaal venster elementen midden op de pagina? Dan zijn er twee andere oplossingen. Maak het venster modaal, zodat de gebruiker het eerst moet sluiten. Of laat een melding die geen actie vraagt vanzelf sluiten zodra de focus ervan af gaat.

Vereisten en aanbevelingen voor toegankelijke focusindicatoren

Dit zijn de vereisten en aanbevelingen voor zichtbare focus en focusindicatoren.

WCAG-vereisten

  • Elk element dat te bereiken is met het toetsenbord heeft een zichtbare focusindicator. Als het element focus heeft, dan is die indicator zichtbaar en blijft het zichtbaar tot de focus wordt verplaatst.
  • Verwijder outline nooit zonder een zichtbare vervanging. outline: none zonder alternatief is een directe fout.
  • De focusindicator die je zelf opmaakt heeft minstens 3:1 contrastverhouding ten opzichte van aangrenzende kleuren. (Voor een onaangepaste browserstandaard geldt deze contrasteis niet.)
  • Een gefocust element wordt niet volledig bedekt door zwevende of meebewegende content die jij als maker op de pagina zet, zoals een sticky header, cookiebanner of chatwidget.

Aanbevolen

  • Gebruik een tweekleurige focusindicator. Zo werkt je indicator op alle achtergrondkleuren in je ontwerp, zonder per component een aparte kleur te kiezen.
  • Gebruik outline als primair stijlmechanisme, niet alleen box-shadow. In Windows forced colors mode valt box-shadow weg.
  • Voeg scroll-padding-top en scroll-padding-bottom toe als je site een sticky header, sticky footer of vaste banner heeft.

Om te onthouden

Een zichtbare focusindicator is voor toetsenbordgebruikers het enige houvast op de pagina. Zorg dat de indicator goed zichtbaar is, genoeg contrast heeft en niet onder overlappende content verdwijnt.

Ontdek het zelf eens: leg je muis weg en tab door je eigen pagina. Zie je bij elke stap waar je bent? Ben je ontwikkelaar, zoek dan daarna in je CSS naar outline: none en outline: 0. Staat daar geen eigen :focus-visible-stijl tegenover? Dan heb je je eerste fout te pakken.

Gerelateerde succescriteria

Dit artikel behandelt de volgende WCAG-succescriteria:

  1. 2.4.7 Focus zichtbaar (niveau AA)
  2. 2.4.11 Focus niet bedekt (minimum) (niveau AA)
  3. 1.4.11 Contrast van niet-tekstuele content (niveau AA)
  4. 2.4.12 Focus niet bedekt (uitgebreid) (niveau AAA)
  5. 2.4.13 Focusweergave (niveau AAA)

Laatst gewijzigd op

Niek Derksen

Ik ben onderzoeker digitale toegankelijkheid bij WCAG.nl, onderdeel van VoorMeerWaarde. In ruim 8 jaar heb ik meer dan 400 toegankelijkheidsonderzoeken uitgevoerd voor overheidsorganisaties en commerciële bedrijven. De inzichten uit die onderzoeken deel ik op deze website.

Vragen of aanvullingen? Laat het weten

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *