WCAG-kleurcontrast halen zonder te gokken

Wat een contrastverhouding meet, de AA- en AAA-drempels voor tekst en interfaceonderdelen, en de fouten met grijs op wit die stilletjes elke keer zakken.

Voor gewone lopende tekst vraagt WCAG-niveau AA om een contrastverhouding van minstens 4,5:1 met de achtergrond. Grote tekst heeft 3:1 nodig. Interfaceonderdelen en betekenisdragende afbeeldingen hebben 3:1 nodig. Niveau AAA tilt tekst naar 7:1, en grote tekst naar 4,5:1. Verhoudingen lopen van 1:1 (identieke kleuren) tot 21:1 (puur zwart op puur wit).

Je kunt dit niet op het oog beoordelen. Twee combinaties die op jouw monitor even leesbaar lijken, kunnen aan weerszijden van de drempel liggen, dus de verhouding moet berekend worden.

De drempels

Waar het om gaatAAAAA
Gewone tekst4,5:17:1
Grote tekst3:14,5:1
Interfaceonderdelen en grafische objecten3:1geen hogere eis

Deze komen uit drie succescriteria: 1.4.3 Contrast (Minimum) op AA, 1.4.6 Contrast (Enhanced) op AAA, en 1.4.11 Non-text Contrast op AA, dat over de visuele begrenzing van bedieningselementen gaat en over de delen van afbeeldingen die je nodig hebt om ze te begrijpen.

Grote tekst betekent minstens 18 punt, of 14 punt als hij vet is, wat neerkomt op ongeveer 24px normaal of zo'n 18,5px vet. Het betekent niet "een kop": een kop van 20px is voor de regels gewone tekst en heeft de volle 4,5:1 nodig.

Een paar dingen zijn uitgezonderd: puur decoratieve tekst, tekst in een inactief bedieningselement, tekst die deel uitmaakt van een afbeelding met andere betekenisvolle visuele inhoud, en logo's. Placeholder- en hulptekst zijn niet uitgezonderd.

Wat de verhouding werkelijk meet

De formule vergelijkt de relatieve luminantie van de twee kleuren:

ratio = (L_lighter + 0.05) / (L_darker + 0.05)

Relatieve luminantie is een getal van 0 (zwart) tot 1 (wit) dat weergeeft hoeveel licht een kleur uitstraalt. Het wordt berekend door de sRGB-gammacurve op elk kanaal ongedaan te maken en ze daarna te wegen:

L = 0.2126 R + 0.7152 G + 0.0722 B     (on linearised channels)

De 0.05 die aan beide kanten wordt opgeteld, modelleert een beetje omgevingslicht dat op het scherm weerkaatst, en daarom is het maximum 21 en niet oneindig.

Daaruit volgen twee dingen. De verhouding hangt alleen van luminantie af, niet van kleurtoon, dus twee kleuren kunnen enorm in toon verschillen en toch vrijwel onzichtbaar tegen elkaar zijn. En hij is symmetrisch, dus het maakt niet uit welke kleur je de voorgrond noemt.

Relatieve luminantie is geen helderheid

Kijk naar die wegingsfactoren. Groen levert ongeveer 72% van de luminantie, rood ongeveer 21%, en blauw amper 7%. Dat is een model van het menselijk zicht, niet van hoe fel een kleur oogt, en het levert resultaten op die verkeerd aanvoelen tot je eraan gewend raakt.

  • Puur geel #FFFF00 op wit is ongeveer 1,07:1, bijna onzichtbaar, ook al voelt geel als een sterke kleur.
  • Datzelfde geel op zwart is ongeveer 19,6:1, bijna net zo hoog als wit op zwart.
  • Puur blauw #0000FF op zwart is ongeveer 2,4:1 en zakt overal voor, al ziet het er stevig en verzadigd uit.

Daarom is de lightness uit HSL ook een slechte benadering. Twee kleuren kunnen allebei op 50% lightness in HSL zitten en sterk verschillende luminantie hebben, omdat HSL kleurtoon en lichtheid als onafhankelijk behandelt en het zicht dat niet doet. Converteer eerst en meet daarna, in plaats van aan te nemen dat een stap in lichtheid een stap in contrast is.

De fouten die zich blijven herhalen

Grijze lopende tekst op wit. Dit is de grote. Het lichtste grijs dat op wit voor AA slaagt is ongeveer #767676, wat uitkomt op 4,54:1. Eén stap lichter, #777777, is 4,48:1 en zakt. Populaire gedempte grijstinten zoals #999999 komen rond 2,9:1 uit, minder dan twee derde van de eis. Wil je AAA op wit, dan heb je ruwweg #595959 nodig, precies 7:1.

Placeholder- en hulptekst. Die worden een paar tinten lichter gezet dan de lopende tekst omdat ze secundair zijn. Het is nog steeds tekst en die heeft nog steeds 4,5:1 nodig.

Halftransparante kleuren. Een verhouding die uit de opgegeven kleur is berekend, zegt niets als het element op 60% dekking staat. Bereken de samengestelde kleur die daadwerkelijk op het scherm verschijnt en meet die.

Tekst over afbeeldingen, kleurverlopen en video. De verhouding verandert van pixel tot pixel en de slechtste pixel is de pixel die telt. De gebruikelijke oplossing is een verdonkerend vlak achter de tekst in plaats van hopen dat de foto donker blijft.

Knoppen in een merkkleur. Witte tekst op een merkkleur van middentoon komt heel vaak tussen 3:1 en 4,5:1 uit, waarmee hij als grafisch object slaagt en als label zakt. Maak de knop donkerder, of accepteer bewust dat hij zakt.

Focusindicatoren en knoppen met alleen een pictogram. Beide vallen onder de 3:1-regel voor niet-tekstuele onderdelen. Een focusring in een iets andere tint van dezelfde kleur is een veelgemaakte misser, net als een grijs pictogram dat de enige inhoud van een knop is.

Donkere modus door omkering. Een licht palet omdraaien behoudt de verhoudingen niet, omdat luminantie niet symmetrisch rond het midden ligt. Puur wit op puur zwart geeft het maximum van 21:1, maar veel mensen vinden de nagloed onprettig, dus gebroken wit op zeer donkergrijs, zoals #E6E6E6 op #121212 met ongeveer 15:1, is een gangbaar compromis.

Meten vanaf een schermafbeelding. Een pipet op de rand van geanti-aliaste tekst bemonstert een mengsel van tekst en achtergrond, niet de tekstkleur. Bemonster het midden van een dikke streek, of beter, lees de waarden uit je CSS.

Een werkwijze die gokken uitsluit

Leg eerst de achtergrond vast, maak dan de voorgrond donkerder of lichter tot hij de drempel met wat marge haalt, en noteer dat paar. Bouw het palet op uit goedgekeurde paren in plaats van goedgekeurde kleuren: een kleur is niet op zichzelf toegankelijk, alleen in combinatie. Controleer ook elke toestand, niet alleen de rusttoestand, en beide thema's als je een donkere modus uitlevert.

Nog één opmerking. Een nieuwer perceptueel model, APCA, wordt ontwikkeld voor een toekomstige versie van WCAG en gedraagt zich behoorlijk anders, vooral bij lichte tekst op een donkere achtergrond. Het is goed om te kennen, maar de cijfers waaraan je vandaag moet voldoen zijn de WCAG 2-verhoudingen hierboven.