Twee kleuren hebben alleen als paar een contrastverhouding, en het getal waar een audit op afgaat is dat van WCAG 2. Deze pagina zet er een APCA-score naast, want juist bij lichte tekst op donker, waar interfaces tegenwoordig uit bestaan, lopen die twee het verst uiteen. Zakt een niveau, dan krijgen tekst en achtergrond aparte suggesties, want een van de twee ligt meestal al vast door een merk en de tool kan niet weten welke.
De verhouding is een luminantiequotiënt, en groen is 72% van de luminantie
De WCAG 2-contrastverhouding is (L1 + 0.05) / (L2 + 0.05), waarbij L1 de relatieve luminantie van de lichtste kleur is en L2 die van de donkerste. Relatieve luminantie neemt elk 8-bits sRGB-kanaal, deelt door 255, draait de transfercurve van het scherm terug, en weegt de drie uitkomsten 0,2126 rood, 0,7152 groen, 0,0722 blauw. Die wegingen zijn het grootste deel van wat het getal meet: #00ff00 op zwart scoort 15,3:1 en #0000ff op zwart scoort 2,4:1, want het oog haalt bijna zijn hele luminantiesignaal uit groen en bijna niets uit blauw. De twee termen van 0,05 staan voor licht dat in een gemiddelde kamer op het scherm weerkaatst, en die begrenzen de schaal ook op 21:1, zwart op wit. De definities staan in WCAG 2.2 en zijn onveranderd sinds WCAG 2.0.
De verhouding is symmetrisch omdat de formule de twee luminanties op volgorde zet voordat hij deelt. Tekst en achtergrond omdraaien geeft precies hetzelfde getal, en daarom biedt deze pagina een wisselknop in plaats van twee aparte metingen: de WCAG-oordelen blijven staan, de APCA-score en het voorbeeld niet. Een kleur met alpha wordt eerst over de achtergrond gelegd, want een doorschijnende kleur heeft geen eigen luminantie.
De WCAG 2-formule is onbetrouwbaar op donkere achtergronden
De verhouding van WCAG 2 vleit lichte tekst op donkere achtergronden, en het paar dat hier standaard staat is het bewijs: #9aa0a6 op #202124 is de secundaire tekst uit het donkere thema van Google op hun eigen donkere vlak. Het scoort 6,10:1, ruim boven de 4,5:1 van AA, en op 14px leest het als grijze brij. APCA zet datzelfde paar op Lc -48, ver onder de Lc 75 die het voor lopende tekst vraagt.
Daar zijn twee oorzaken voor. De formule is een verhouding en geen verschil, dus aan de donkere kant overheerst de vaste term van 0,05 voor strooilicht in allebei de helften, waardoor kleine luminantieverschillen opblazen tot grote verhoudingen. En waargenomen contrast is niet symmetrisch, zoals het rekenwerk wel is: een lichte letter op een donker vlak bloeit aan de randen uit, en dat wordt erger met astigmatisme en met de dunne letterdiktes die donkere interfaces graag gebruiken. WCAG 2 kent bovendien geen letterdikte, dus een label van 300 en een van 700 op dezelfde grootte krijgen precies hetzelfde oordeel.
Wat APCA verandert, en wat niet
APCA, het Accessible Perceptual Contrast Algorithm, is een andere meting en geen herschaalde verhouding. Het is perceptueel, afgestemd op gemeten leesbaarheid in plaats van afgeleid uit een luminantiequotiënt. Het is polariteitsbewust: apca(tekst, achtergrond) is niet symmetrisch, en het teken legt vast welke kant het paar op staat, negatief voor lichte tekst op donker. En het is bewust van dikte en grootte: het publiceert de Lc die elke grootte en dikte nodig heeft in plaats van één getal voor alle tekst. #767676 op wit is Lc 71,6; wit op #767676 is Lc -77,0. WCAG geeft allebei de paren 4,54:1. Een Lc is geen verhouding: de schaal loopt tot ongeveer 106, en Lc 60 is niet 60:1 en er ook niet naar om te rekenen. De cijfers hier zijn revisie 0.1.9, constantenset G-4g, en dat telt omdat Lc-waarden per revisie verschuiven.
De eerlijke beperking: APCA is informatief en is geen conformiteitscriterium van WCAG 2. Het is een kandidaatmethode voor WCAG 3, een Working Draft zonder normatieve status en zonder publicatiedatum, dus vandaag rust er niets juridisch of contractueel op een Lc. Een audit tegen WCAG 2.0, 2.1 of 2.2, en daarmee tegen EN 301 549, Section 508 en de European Accessibility Act, wordt alleen door de verhouding beslecht. Stuur op de verhouding. Lees de Lc pas als de verhouding slaagt en de tekst er nog steeds verkeerd uitziet; daar is hij voor bedoeld.
Grote tekst is 18,66px vet of 24px normaal
Dit is de meest verkeerd gelezen regel in het criterium. WCAG definieert grote tekst als minstens 18 punt, of 14 punt vet, en bij de CSS-referentieresolutie van 96dpi is dat 24px en 18,66px. Het is een maat, geen rol: een subkop van 24px normaal telt mee en heeft bij AA maar 3:1 nodig, terwijl een van 18px vet niet meetelt en de volle 4,5:1 nodig heeft. Of je een element een kop noemt, doet er niets toe. Twee van de voorbeeldregels hierboven staan precies op die groottes; het voorbeeld toont er vijf omdat het criterium er twee onderscheidt en je oog alle vijf.
Waarom deze tool 0.03928 gebruikt en niet 0.04045
De drempel in de gepubliceerde WCAG-tekst voor de overgang tussen het lineaire deel en het machtsdeel van de sRGB-transfercurve is 0.03928, en dat is het verkeerde getal. De delen raken elkaar in werkelijkheid op 0.04045; de kleinere waarde is een afrondingsartefact uit een vroege sRGB-versie dat nooit in de WCAG-tekst is rechtgezet. Het verschuift de luminantie alleen voor kanaalwaarden in een smalle strook rond 10/255, veel te weinig om een geslaagd paar te laten zakken. Deze tool gebruikt met opzet de gepubliceerde 0.03928, zodat de verhoudingen overeenkomen met wat een auditor krijgt die uit de specificatie rekent. Als een andere checker op een heel donkere kleur in het derde decimaal afwijkt, is dat meestal de reden.
Veelvoorkomende problemen
- Het slaagt en het ziet er toch verkeerd uit. Kijk naar het polariteitslabel. Staat het op licht op donker, lees dan de Lc: precies daar is de verhouding het minst te vertrouwen, en de oplossing is meestal een zwaardere letterdikte of een lichtere tekstkleur in plaats van een donkerdere achtergrond.
- De tekst staat op een afbeelding, een verloop of een video. Er is niet één achtergrondkleur, dus test de slechtste: de lichtste pixel waar de tekst overheen loopt als de tekst licht is, de donkerste als de tekst donker is. Een halftransparant vlak achter de tekst is de gebruikelijke oplossing.
- Placeholdertekst is niet uitgezonderd. De uitzonderingen bij 1.4.3 gelden voor bijkomstige tekst, logo's en inactieve bedieningselementen. Een placeholder in een actief invoerveld is levende tekst en moet 4,5:1 halen, en daarom zakken er zoveel grijze placeholders in een audit.
- Pictogrammen en randen vallen onder een andere regel. Niet-tekstcontrast is 1.4.11, toegevoegd in WCAG 2.1, en dat vraagt 3:1 van pictogrammen, invoerranden, focusringen en legenda's van grafieken tegen wat ernaast ligt. Test die paren hier tegen de rij van 3:1.
- De suggestie lijkt niet op je merkkleur. Hij houdt tint en chroma vast en verschuift alleen de OKLCH-lichtheid, de as waar contrast van afhangt. Leest de verschuiving toch als een andere kleur, dan zit het paar zo ver van slagen af dat er iets anders dan de tekstkleur moet wijken.
Veelgestelde vragen
Is 4,5:1 eigenlijk genoeg?
Het is de wettelijke ondergrens, geen doel. 4,5:1 is gekozen om ongeveer 20/40 gezichtsscherpte te dekken, ruwweg het verlies dat hoort bij 80 jaar, en het gaat uit van een gezond scherm bij redelijk licht. AAA vraagt 7:1 van dezelfde tekst. Zie bij 16px lopende tekst 4,5:1 als de grens waaronder je een defect hebt, en iets richting 7:1 als de grens waarboven niemand meer klaagt.
Heeft WCAG 2.2 een van deze getallen veranderd?
Nee. Succescriteria 1.4.3 (Contrast Minimum, AA) en 1.4.6 (Contrast Enhanced, AAA) zijn onveranderd sinds WCAG 2.0 uit 2008, via 2.1 uit 2018 en 2.2 uit 2023. WCAG 2.2 voegde criteria voor focus en doelgrootte toe en schrapte 4.1.1 Parsing; aan het contrastrekenwerk veranderde niets. De volgende wijziging daarin is WCAG 3, en dat duurt nog jaren.
Maakt het uit welke kleur ik eerst invoer?
Voor de verhouding niet, die is symmetrisch. Voor de rest wel. De APCA-score verandert van teken en van grootte, het voorbeeld tekent een ander paar, en de suggesties verschuiven een andere kleur. Voer ze in zoals ze op het scherm staan en gebruik de wisselknop om de andere polariteit te zien.
Hoe controleer ik een heel palet in plaats van een paar?
Test de paren die je gaat leveren, niet de matrix van alles tegen alles: lopende tekst op elk vlak, gedempte tekst op elk vlak, en elke interactieve kleur op het vlak waar hij verschijnt. Haal de paren die betekenis dragen ook door de kleurenblindheidssimulator. Contrast en kleuronderscheid zijn aparte problemen, en een paar kan het ene halen en het andere niet.
Verlaat mijn invoer de browser?
Nee. De luminantie, de verhouding, de APCA-score en het zoeken naar lichtheid draaien allemaal in dit tabblad, zonder verzoek om ze ergens heen te sturen. De twee kleuren staan alleen in de parameters ?fg= en ?bg= zodat een link teruggeeft waar je naar kijkt. De kleurformaatconverter en de rest van de kleurtools werken op dezelfde manier.