WCAG-contrastverhouding: AA, AAA en APCA, de complete gids voor 2026
Je levert een knop op. Merkoranje, witte tekst, ziet er knapperig uit op je 4K-monitor. Dan komt de toegankelijkheidsaudit rood terug: de WCAG-contrastverhouding is 1,97:1, nergens in de buurt van de 4,5:1-drempel die AA voor bodytekst eist. Die knop die er voor jou prima uitziet, is onleesbaar voor zo’n 220 miljoen mensen met slechtziendheid wereldwijd. Deze gids loopt elk getal door dat je nodig hebt om dat te repareren: WCAG 2-ratio’s, het AAA-niveau, het nieuwe APCA Lc-algoritme, acht categorieën kleurzichtafwijkingen en een werkende JavaScript-implementatie die je zo in je build kunt droppen.
Snelle referentie: WCAG- en APCA-drempels in één oogopslag
| Standaard | Normale tekst | Grote tekst | UI / iconen | Opmerking |
|---|---|---|---|---|
| WCAG AA | ≥ 4,5:1 | ≥ 3:1 | ≥ 3:1 | Wettelijke basis |
| WCAG AAA | ≥ 7:1 | ≥ 4,5:1 | ≥ 3:1 | Verhoogde doelstelling |
| APCA body | Lc 75+ | Lc 60+ | Lc 45+ (iconen) | Concept, perceptueel |
“Grote tekst” betekent ≥ 18pt regular of ≥ 14pt bold (≈ 24px en ≈ 18,66px in CSS). “UI” dekt formulierranden, focusringen en elk grafisch element dat een gebruiker moet waarnemen om de pagina te kunnen bedienen. Logo’s en puur decoratieve afbeeldingen vallen buiten de contrasteisen.
Wat is WCAG-kleurcontrast?
WCAG-contrastverhouding is een numerieke maat van 1:1 (geen contrast) tot 21:1 (maximaal) die de relatieve luminantie van tekst vergelijkt met de achtergrond. De Web Content Accessibility Guidelines eisen ≥ 4,5:1 (AA) voor bodytekst of ≥ 7:1 (AAA) voor verhoogde compliance.
Die ene verhouding stuurt wereldwijd de meeste toegankelijkheidsaudits. De W3C publiceerde hem in WCAG 2.0 al in 2008, verfijnde hem in 2.1 (2018) en 2.2 (2023), en elke grote toezichthouder verwijst er inmiddels naar. De ADA in de Verenigde Staten, de European Accessibility Act (handhaafbaar sinds juni 2025), Section 508 voor Amerikaanse federale instanties en de Canadese AODA gebruiken allemaal WCAG 2.x AA als de facto ondergrens.
Waarom is dit relevant naast het juridische argument? Wereldwijd hebben zo’n 220 miljoen mensen slechtziendheid zonder blind te zijn; ze lezen wel schermen, maar alleen als het contrast tussen tekst en achtergrond hoog genoeg is. Ongeveer 8% van de mannen en 0,5% van de vrouwen heeft een kleurzichtafwijking. Oudere lezers ervaren vergeling van de lens en een kleinere pupilopening, wat het waargenomen contrast functioneel met 20–30% verlaagt na het zestigste levensjaar. Buitengebruik van een smartphone kost nog eens 20–40% door reflectie. Een pagina die 4,5:1 scoort op je bureau is de ondergrens waarop al die gebruikers nog kunnen meelezen.
De mensen die zich hier het meest om moeten bekommeren zijn front-endengineers die productie-UI opleveren, ontwerpers die merkpaletten kiezen, toegankelijkheidsspecialisten die audits draaien, en compliance-teams die verantwoordelijk zijn voor de juridische blootstelling. De wiskunde is kort. De keuzes die het afdwingt zijn dat niet.
WCAG 2.x-contrastverhouding: de wiskunde, de drempels
De W3C definieert contrast in drie korte stappen. Om de WCAG-contrastverhouding te berekenen: (1) zet elke kleur om van gamma-encoded sRGB naar lineaire lichtwaarden, (2) bereken de relatieve luminantie met vaste coëfficiënten voor de gevoeligheid van het menselijk oog voor rood, groen en blauw, en (3) deel de twee luminanties met een kleine constante offset om bijna-zwarte waarden af te vangen.
De formule voor relatieve luminantie uit WCAG 2.1 §1.4.3 luidt:
L = 0.2126 × R_lin + 0.7152 × G_lin + 0.0722 × B_lin
R_lin, G_lin en B_lin zijn de lineaire kanaalwaarden nadat de sRGB-gammacurve is teruggedraaid. De factor 0.7152 op groen weerspiegelt de sterke groengevoeligheid van het oog: groen is per eenheid lichtenergie ruwweg 7× visueel luider dan blauw.
De ratioformule luidt:
ratio = (L_lighter + 0.05) / (L_darker + 0.05)
De +0.05 voorkomt deling door nul voor puur zwart (L = 0) en geeft een maximum van (1 + 0.05) / (0 + 0.05) = 21:1 voor zuiver wit op zuiver zwart. Het minimum is 1:1, identieke kleuren.
Hier is de volledige implementatie in ongeveer dertig regels vanilla JavaScript. Geen afhankelijkheden, draait overal:
// sRGB hex → lineair lichtkanaal
function srgbToLinear(channel8bit) {
const v = channel8bit / 255;
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}
// "#RRGGBB" → relatieve luminantie [0, 1]
function relativeLuminance(hex) {
const h = hex.replace("#", "");
const r = parseInt(h.slice(0, 2), 16);
const g = parseInt(h.slice(2, 4), 16);
const b = parseInt(h.slice(4, 6), 16);
return (
0.2126 * srgbToLinear(r) +
0.7152 * srgbToLinear(g) +
0.0722 * srgbToLinear(b)
);
}
// WCAG 2.x-contrastverhouding tussen twee hex-kleuren
function contrastRatio(hexA, hexB) {
const lA = relativeLuminance(hexA);
const lB = relativeLuminance(hexB);
const [lighter, darker] = lA > lB ? [lA, lB] : [lB, lA];
return (lighter + 0.05) / (darker + 0.05);
}
// Voorbeeld: donkere slate bodytekst op wit
console.log(contrastRatio("#475569", "#ffffff").toFixed(2));
// → "7.58", ruim boven AA 4,5:1 en net boven AAA 7:1
Gooi twee hex-codes in de Kleurconverter en dezelfde getallen rollen eruit, naast een APCA Lc-waarde, een gamutclassificatie en een previewtegel met acht CVD-varianten. De drempels zelf zijn concreet:
| Element | AA min | AAA min | Opmerking |
|---|---|---|---|
| Normale bodytekst | 4,5:1 | 7:1 | Onder 18pt regular / onder 14pt bold |
| Grote tekst | 3:1 | 4,5:1 | ≥ 18pt regular OF ≥ 14pt bold |
| UI-componenten / iconen | 3:1 | — | WCAG 2.1 §1.4.11, toegevoegd in 2018 |
| Logo’s en decoratief | uitgezonderd | uitgezonderd | Geen contrasteis |
De CSS-eenheidsconversies struikelen veel teams. 18pt = 24px bij de browser-default, 14pt = 18,66px. Een 16px-bodyfont, de moderne default, zit onder de “grote tekst”-drempel en valt dus onder de strengere AA-regel van 4,5:1. Een 20px-kop op font-weight: 700 kwalificeert wel als groot en krijgt de soepelere 3:1.
Eén subtiliteit die teams onverwacht raakt: de “grote tekst”-uitzondering in WCAG gaat over leesbaarheid op grotere schaal, niet over kop-semantiek. Een 14px <h2> is geen grote tekst en moet nog steeds 4,5:1 halen. Een 24px-marketingparagraaf is grote tekst en krijgt de ondergrens van 3:1. De regel hangt aan de gerenderde pixelmaat en gewicht, nooit aan de tagnaam. Auditors melden mismatches; jouw CSS is de bron van waarheid, niet je HTML-semantiek.
De constante +0.05 in de ratioformule heeft een specifieke oorsprong: het is de flare-term, het omgevingslicht dat van het schermoppervlak terugkaatst en de waargenomen luminantie van puur zwart optilt tot een minimumvloer. Zonder die term zou een OLED-pixel die echt zwart rendert tegenover zuiver wit een deling door nul geven. Mét die term is het maximaal haalbare 21:1, een getal dat je in elke toegankelijkheidstool tegenkomt. Er is geen fysiek scherm dat meer dan 21:1 levert zodra flare wordt meegerekend, en daar stopt de WCAG-schaal dan ook.
AA versus AAA: welk niveau moet je nastreven?
AA is de wettelijke ondergrens; AAA is het aspirationele niveau. De meeste commerciële sites richten zich op AA omdat AAA merkkleuren richting grijstinten dwingt, iets wat de meeste marketingteams weigeren. De afweging is niet “meer is beter”, maar een trade-off tussen bereik onder gebruikers en merkexpressie.
| Context | Aanbevolen niveau | Reden |
|---|---|---|
| Algemene commerciële site | AA | ADA-/EAA-compliance-basis; rechtbanken citeren WCAG 2 AA |
| Overheid / publieke diensten | AAA | Section 508 en gelijkwaardige EU-wetten bevelen AAA aan |
| Zorg / onderwijs | AAA | Gebruikersbasis leunt naar hogere toegankelijkheidsbehoefte |
| Intern dashboard | AA | Publiek bekend; ROI-afweging acceptabel |
| Marketing-landingspagina | AA + merkuitzondering | Merkkleuren toegestaan op hero/CTA’s, body blijft AA |
De verborgen kosten van AAA tonen zich de eerste keer dat je een verzadigd merkoranje door 7:1 op wit wilt loodsen. Het lukt niet. Je verduistert het oranje tot het je merk niet meer is, of je accepteert AA en zet het oranje in op donkere achtergronden, waar het wel zonder moeite AAA haalt. Veel bedrijven, ook de meer toegankelijkheidsbewuste, mikken expliciet op AA voor bodycontent en duwen alleen kritische tekst zoals foutmeldingen of juridische disclosures door naar AAA.
Toezichthouders hebben niet gewacht tot AAA zich verspreidt. De webtoegankelijkheidsregeling van de ADA uit 2024 verwijst naar WCAG 2.1 AA. De European Accessibility Act, handhaafbaar sinds juni 2025, eist WCAG 2.1 AA over alle gedekte digitale diensten. Section 508 in de Amerikaanse federale overheid gebruikt WCAG 2.0 AA als basis (met AAA aanbevolen waar haalbaar). De Canadese AODA, de toegankelijkheidswet van Ontario, verwijst naar WCAG 2.0 AA. Het patroon is consistent: AA is de lat, AAA is het doel.
APCA: het nieuwe perceptuele algoritme
APCA (het Advanced Perceptual Contrast Algorithm, ontworpen door Andrew Somers onder het Myndex-label) is een kandidaat-algoritme voor WCAG 3. Het vervangt de symmetrische ratio van WCAG 2 door een polariteitsgevoelige Lc-score van -108 tot +108, waarbij het teken aangeeft in welke richting het contrast loopt (donkere tekst op licht versus lichte tekst op donker) en de grootte het waargenomen contrast op een echt emissief display weerspiegelt.
APCA doet ertoe omdat de symmetrische formule van WCAG 2 twee effecten uit de praktijk mist:
- Polariteitsasymmetrie. Lichte tekst op een donkere achtergrond leest anders dan donkere tekst op een lichte achtergrond, zelfs bij dezelfde WCAG-ratio. WCAG 2 geeft voor beide richtingen hetzelfde getal; APCA niet.
- Displaymodellering. De formule van WCAG 2 is afgeleid van luminantiemodellen voor papier. APCA is geijkt op sRGB-displays in typisch kantoorlicht, wat dichter ligt bij wat je gebruikers daadwerkelijk zien.
De trade-off: APCA is complexer (het bevat polariteitsbewuste exponenten en font-weight-correcties) en is nog geen regelgevingsstandaard. De analyse van Adrian Roselli uit april 2026 blijft de helderste samenvatting van waar APCA staat: het is technisch veelbelovend, maar WCAG 3 zelf zit nog in een vroege conceptfase op het Silver-traject, en APCA is nog niet bekrachtigd als het officiële algoritme.
De APCA Bronze-drempels (de praktische ondergrens waar de meeste teams op mikken) zien er zo uit:
| Toepassing | Aanbevolen Lc | Minimum Lc |
|---|---|---|
| Bodytekst (16px, gewicht 400) | 90+ | 75 |
| Grote tekst (24px, gewicht 400) | 75+ | 60 |
| UI-elementen en niet-tekstuele iconen | 60+ | 45 |
| Spot-tekst / placeholders | 30+ | 30 |
APCA is interessant juist op de plekken waar het niet met WCAG 2 overeenstemt; daarom toont de Kleurconverter beide metrieken naast elkaar:
#FFA500(oranje) op#FFFFFF: WCAG 2 geeft 1,97:1, een duidelijke buis op AA. APCA is het eens en scoort rond Lc 38, ook een buis. Tot zover zeggen beide algoritmes nee, en toch zie ik ontwerpers deze combinatie keer op keer doorzetten omdat “het er prima uitziet”.#767676(midgrijs) op#FFFFFF: WCAG 2 geeft 4,54:1, net boven AA 4,5:1, technisch een pass. APCA scoort dit paar op ongeveer Lc 60, wat onder de Bronze-drempel van 75 voor bodytekst ligt. WCAG geslaagd; APCA gezakt. De geleefde ervaring van de gebruiker ligt dichter bij het oordeel van APCA: dat grijs op wit moeilijker leest op bodyformaat dan de ratio doet vermoeden.#3b82f6(Tailwind blue-500) op#000000: WCAG 2 geeft 5,71:1, een AA-pass met ruimte. APCA scoort dit rond Lc 65, onder het minimum van Lc 75 voor bodytekst. Lichte blauwe tekst op een donkere achtergrond, het geliefde dark-mode-patroon, is hét voorbeeld van “WCAG geslaagd, APCA waarschuwt”.
Je hoeft geen kant te kiezen. De pragmatische lijn waarop de meeste productie-teams uitkomen: houd WCAG 2 AA aan als regelgevingsbasis, want dat is wat compliance-audits toetsen, en draai APCA er parallel naast als “is dit eigenlijk wel leesbaar?”-onderbuikcheck, vooral voor dark-mode-ontwerpen en verzadigde merkkleuren. De Kleurconverter toont beide getallen op één rij, zodat je niet hoeft te schakelen tussen checkers.
Kleurenblindheid en wat verder gaat dan contrast
Contrastverhoudingen zijn maar de helft van kleurtoegankelijkheid. Ongeveer 8% van de mannen en 0,5% van de vrouwen ziet kleuren anders dan de leerboek-trichromat, en de meest voorkomende variant, deuteranomalie, zit precies in het midden van het rood/groen-paar dat we overal gebruiken voor success-/error-staten. WCAG 1.4.1 (“Use of Color”) verbiedt expliciet dat kleur het enige drager van informatie is; dat is de regel die hier op staat.
De volledige taxonomie van kleurzichtverschillen valt uiteen in drie groepen: dichromacy (één type kegeltje ontbreekt), anomale trichromacy (één type kegeltje is verschoven) en de zeldzame monochromacieën.
| Type | Volksnaam | Aangedaan kanaal | Prevalentie (M / V) |
|---|---|---|---|
| Protanopia | Roodblind | L-kegel afwezig | 1,0% / 0,01% |
| Deuteranopia | Groenblind | M-kegel afwezig | 1,1% / 0,01% |
| Tritanopia | Blauwblind | S-kegel afwezig | 0,003% / 0,003% |
| Protanomalie | Roodzwak | L-kegel verschoven | 1,3% / 0,02% |
| Deuteranomalie | Groenzwak | M-kegel verschoven | 5,0% / 0,4% |
| Tritanomalie | Blauwzwak | S-kegel verschoven | 0,01% / 0,01% |
| Achromatopsia | Geen kleur | Alle kegels afwezig | 0,003% (zeer zeldzaam) |
| Kegelmonochromacie | Gedeeltelijk grijs | Slechts één kegel | 0,001% |
Alleen deuteranomalie al raakt 5% van de mannen, één op de twintig. Dat is de groep die een rode foutindicator en een groene succesindicator ziet als ongeveer dezelfde olijfbruine tint. De oplossing is niet om je hele kleursysteem te herontwerpen; het is om een tweede kanaal toe te voegen. Een rood fouticoon gekoppeld aan een ”ד-vorm en het woord “Fout” overleeft elke variant in de tabel. Een kale rode stip niet.
CVD simuleren in code gebruikt twee standaard matrixsets: Brettel–Viénot–Mollon (1997) voor de dichromacieën en Machado–Oliveira–Fernandes (2009) voor de anomale trichromacieën. De Brettel-aanpak projecteert de invoerkleur van de gebruiker op een vlak dat wordt opgespannen door de twee overgebleven kegelresponsen; Machado parametriseert de kegelverschuiving op ernst. Beide zijn implementeerbaar als SVG-filter of CSS-matrix. De Kleurconverter levert alle acht varianten als previews met één klik, zodat je een merkkleur door het spectrum heen kunt scannen zonder de pagina te verlaten.
Een kort SVG-filter (plak in je pagina en verwijs via ID) geeft je in-browser protanopia-simulatie voor ad-hoctesten:
<svg style="display: none">
<filter id="protanopia">
<feColorMatrix type="matrix" values="
0.567 0.433 0.000 0 0
0.558 0.442 0.000 0 0
0.000 0.242 0.758 0 0
0.000 0.000 0.000 1 0"/>
</filter>
</svg>
<style>
.preview-protanopia { filter: url(#protanopia); }
</style>
Pas .preview-protanopia toe op je page-wrapper om te zien wat een protanoop ziet. Herhaal met de deuteranopia- en tritanopia-matrices (hun coëfficiënten staan in de Brettel-paper en zitten in de meeste CVD-simulatorbibliotheken). Het Rendering-paneel van Chrome DevTools heeft dezelfde simulators ingebouwd onder “Emulate vision deficiencies”, handig voor snelle checks, minder handig voor het vastleggen van screenshots in CI.
De diepere regel, naast simulatie: laat kleur nooit het enige verschil zijn tussen twee staten. Iconen moeten verschillen in vorm (× versus ✓), staten in tekstlabel (“Fout” versus “Succes”), categorieën in patroon (effen versus gearceerd). Kleur is een multiplier op die andere signalen, geen vervanger.
Er is een klasse fouten die contrastcheckers niet vangen, maar CVD-simulators wel. Taartdiagramsegmenten die alleen op tint van elkaar verschillen, kaartlegenda’s die landen kleurcoderen, statuspillen die op een groen/geel/rood-verloop leunen: die kunnen allemaal door WCAG 2 heen komen tegen de achtergrond, maar onleesbaar zijn voor een deuteranoop die ze tegen elkáár leest. De regel is om leesbaarheid te toetsen tussen aangrenzende kleuren in het ontwerp, niet alleen tegen het omringende canvas. Twee slate-500-segmenten naast elkaar op dezelfde lichtheid zijn niet te onderscheiden, ongeacht hue-rotatie. Voeg een luminantiestap toe tussen aangrenzende vlakken en de grafiek overleeft elke CVD-variant.
Achromatopsia en kegelmonochromacie zijn zeldzaam, maar het ontwerpen ervoor is de moeite waard omdat zij alle tintonderscheid wegslaan. Een gebruiker met achromatopsia neemt alleen luminantie waar: jouw kleurgecodeerde UI ziet er voor hen uit als een grijstintenfoto. Houdt je ontwerp het uit als je filter: grayscale(1) over de hele pagina draait (probeer het in DevTools)? Dan ben je geslaagd voor de strengste versie van de regel “kleur is niet het enige signaal”. Het is de goedkoopste toegankelijkheidstest die je kunt draaien, en hij legt verrassend veel fouten bloot zodra je hem inschakelt.
Auditen van Tailwind- en Material-paletten
Het meeste front-endwerk gebruikt een kant-en-klaar palet: Tailwind v4, Material 3, Radix of shadcn. De toegankelijkheidsvraag wordt “bij welke stop van deze ramp wordt tekst leesbaar?”, en het antwoord is meer vuistregel dan de docs toegeven.
Voor de slate-ramp van Tailwind v4 tegen zuiver wit vallen de WCAG- en APCA-getallen zo:
| Tailwind-klasse | Hex (benadering) | WCAG tegen wit | AA body | AAA body | APCA Lc (benadering) |
|---|---|---|---|---|---|
| slate-400 | #94a3b8 | 2,56:1 | ✗ | ✗ | ~38 ✗ |
| slate-500 | #64748b | 4,76:1 | ✓ | ✗ | ~60 ✗ body |
| slate-600 | #475569 | 7,58:1 | ✓ | ✓ | ~78 ✓ body |
| slate-700 | #334155 | 10,35:1 | ✓ | ✓ | ~90 ✓ body |
De praktische regels die hieruit volgen:
- Bodytekst vraagt slate-600 of donkerder. Slate-500 slaagt voor WCAG AA, maar zakt voor de APCA-drempel voor bodytekst, dus compliant maar oncomfortabel. Slate-600 is de veilige ondergrens.
- UI-labels en secundaire tekst mogen slate-500 gebruiken. UI-componenten hebben maar 3:1 nodig; de 4,76:1 van slate-500 is ruim voldoende, en de tekst draagt meestal ondersteunende visuele context.
- Placeholders mogen slate-400 of nog lichter zijn. Placeholdertekst is uitgezonderd van WCAG 1.4.3 als decoratief alleen als je een zichtbaar label boven het veld laat staan. Inline-label-as-placeholder-patronen moeten de drempel voor bodytekst halen.
- Zuiver zwart op slate-100 / slate-200 is verspilde inkt. Je zit dan op 17:1+; overweeg slate-700 of slate-800 als tekstkleur voor een zachter beeld zonder leesbaarheid op te offeren.
Material 3 hanteert een vergelijkbare tonale paletstructuur. De surface-container-high ligt rond toon 92 (zeer licht); de on-surface rond toon 10 (bijna zwart). Het contrast tussen elke on-surface en elke surface-*-token uit dezelfde familie haalt volgens de spec van Material gegarandeerd AA. Koppel on-surface-variant (toon 30) niet aan surface-container (toon 94) zonder te checken; dat is een echte miss die ik heb zien uitleveren.
Heb je een bestaand palet dat zakt op contrast, dan biedt OKLCH het schoonste herstelpad. In plaats van blind aan hex-codes te morrelen, zet je je kleur om naar OKLCH, houd C (chroma) en H (hue) vast en verlaag L (lichtheid) tot het contrast slaagt. Omdat het L-kanaal in OKLCH echt perceptueel is, blijft de merkherkenning intact terwijl het contrast aanscherpt. De HEX naar OKLCH-tool doet die conversie in één stap; de zusterpost OKLCH uitgelegd behandelt de wiskunde in detail.
Dark mode verdient een eigen alinea. De symmetrische ratio van WCAG 2 keurt per definitie dezelfde combinaties goed in light- als in dark mode. APCA, dat polariteitsbewust is, vlagt regelmatig bodytekst in dark mode als slechter leesbaar dan hetzelfde hex-paar in light mode. Licht-op-donker verliest altijd wat waargenomen contrast ten opzichte van donker-op-licht bij dezelfde numerieke ratio; een bekend effect van hoe het oog adapteert. Draai APCA opnieuw op elk dark-mode-paar voordat je het uitlevert.
Contrastcheckers en CI-workflows
Ontwerpers en engineers hebben elk hun favoriete checker; de praktische vraag is welke combinatie tools je in een echte workflow rijgt. Dit is het veld per 2026:
| Tool | WCAG 2 | APCA | CVD-sim | Paletaudit |
|---|---|---|---|---|
| WebAIM Contrast Checker | ✓ | ✗ | ✗ | ✗ |
| Adobe Color | ✓ | ✗ | ✓ | ✓ |
| Stark (Figma-plug-in) | ✓ | ✓ | ✓ | ✓ |
| Polypane (browser) | ✓ | ✓ | ✓ | ✓ |
| Chrome DevTools-kleurkiezer | ✓ | ✓ (exp.) | ✗ | ✗ |
| axe DevTools | ✓ | ✗ | ✗ | ✓ (paginabreed) |
| Go Tools Color converter | ✓ | ✓ | ✓ (8 types) | ✓ (tints/shades) |
Een workflow die productdruk overleeft ziet er zo uit:
- In Figma draaien ontwerpers Stark op elk frame om gezakte paren vroeg op te sporen. Stark vangt de evidente uitschieters voordat er ook maar één hex-code in de codebase belandt.
- Bij hex-code-overdracht plakken engineers de waarde in de Kleurconverter en krijgen WCAG-ratio + APCA Lc + gamutclassificatie + CVD-preview op één rij. Als het paar dark-mode of verzadigd merk is, vangt de dubbele metriek de “WCAG slaagt, APCA zakt”-gevallen waar Stark naast kan zitten.
- Bij PR-tijd scant
axe-core/playwrightde gebouwde pagina’s op elke contrastovertreding in de gerenderde DOM, inclusief dynamische staten. Dat vangt focusringen, hover-staten en disabled-affordances die statische designbestanden missen. - In QA simuleert het Rendering-tabblad van Chrome DevTools protanopia/deuteranopia/tritanopia voor steekproeven op kritieke flows. De kleurkiezer in DevTools toont bij hover op een element ook nog eens de WCAG-ratio.
Pa11y, Lighthouse CI en @axe-core/playwright exposen allemaal contrastasserties als onderdeel van hun bredere toegankelijkheidsaudits. Geen ervan checkt APCA vandaag; allemaal checken ze WCAG 2. Het realistische compromis luidt “dwing WCAG 2 AA af in CI, doe een sanity-check op APCA Lc handmatig voor merkkleuren en dark mode.”
Een patroon dat de moeite waard is om over te nemen van grotere design-systeem-teams: bak de contrastcheck in je tokenvalidatiestap, niet alleen in QA op paginaniveau. Als je design-tokens compileren uit een bronbestand (JSON, YAML of een TypeScript-module), voeg dan een script toe dat elk --text-* × --surface-*-paar dat het systeem toestaat opsomt en een minimale WCAG-ratio asserteert. Het script draait in milliseconden, vangt regressies wanneer iemand aan een token-waarde sleutelt, en produceert een contrastmatrix die meteen dienst doet als documentatie voor het designteam. De check is onafhankelijk van elke gerenderde pagina; hij werkt puur op de tokens en vangt de fout dus voordat er ook maar één UI live gaat.
Voor ad-hocconversies tijdens deze workflow (schakelen tussen hex, RGB, HSL en OKLCH terwijl je aan het debuggen bent) dekken de spokes HEX naar RGB, HEX naar HSL, HEX naar OKLCH en RGB naar HEX de heen-en-weers naar elk kleurformaat dat je toolchain verlangt.
Veelgemaakte fouten en hoe je ze repareert
Na jaren toegankelijkheidsaudits duiken dezelfde zes fouten steeds weer op. Elk heeft een korte fix:
-
Placeholdertekst in lichtgrijs.
#999999op wit is 2,85:1, zakt voor AA. Verdiep naar#666666(5,74:1, geslaagd voor AA) of, beter, vervang placeholder-as-label-patronen door een blijvend zichtbaar label boven het veld. Placeholders horen geen informatie te dragen. -
Merkoranje knop met witte tekst.
#FFA500op wit is 1,97:1, flink gezakt voor AA. De fix die het merk behoudt is het contrast omdraaien: donkere tekst (bijvoorbeeld#451a03) op het oranje, of de witte tekst houden maar de knop verdiepen naar een diep verzadigd bruinoranje. Verifieer in de Kleurconverter voordat je uitlevert. -
Felle blauwe link in dark mode.
#3b82f6op#000000is 5,71:1, geslaagd voor WCAG AA, maar APCA Lc ~65, onder de bodydrempel van Lc 75. Pak OKLCH erbij en zet L van ≈ 0,63 naar 0,75, terwijl je C en H vasthoudt; je belandt rond#7aa5f8met APCA Lc 80+ en dezelfde hue. -
Disabled tekst in
#CCCCCC. 1,61:1 tegen wit. WCAG 1.4.3 zondert puur decoratieve tekst uit van de ratioregel, maar disabled UI-controls zijn niet decoratief; ze communiceren “dit is op dit moment niet beschikbaar”. Koppel de gedempte kleur aan een niet-kleur-signaal (doorhaling, slot-icoon, “Uitgeschakeld”-tooltip) zodat een CVD- of slechtziende gebruiker de staat alsnog begrijpt. -
Statusiconen die alleen in tint verschillen. Een rode
×en een groene✓is prima, want de vorm onderscheidt ze al. Een rode stip tegenover een groene stip niet. Gebruik vorm en kleur samen; de CVD-preview van de Kleurconverter maakt het faalgeval binnen een seconde duidelijk. -
Tekst over een verloopachtergrond. Een verloop dat van
#3b82f6naar#a78bfaloopt tegen witte tekst slaagt in het midden en zakt aan de lavendelkant. De fix is om het contrast af te dwingen tegen het slechtste punt van het verloop, of er een semi-transparante donkere scrim overheen te leggen zodat de effectieve achtergrondluminantie altijd onder een bekende drempel ligt.
Elke fix kost minuten. De auditcyclus die ze voorkomen, kost weken.
FAQ
Wat is de WCAG AA-contrastverhouding?
WCAG AA eist ≥ 4,5:1 tussen bodytekst en achtergrond, of ≥ 3:1 voor grote tekst (≥ 18pt regular of ≥ 14pt bold) en UI-componenten zoals formulierranden. AA is de wettelijke ondergrens onder ADA, EAA en Section 508; de meeste commerciële sites mikken op AA omdat dat de regelgevende lat haalt zonder merkkleuren naar grijstinten te dwingen.
Welke contrastverhouding heb ik nodig voor AAA?
WCAG AAA eist ≥ 7:1 voor normale bodytekst en ≥ 4,5:1 voor grote tekst. AAA wordt aanbevolen voor medische, educatieve en overheidssites waar de gebruikersbasis leunt naar hogere toegankelijkheidsbehoefte. Merkkleuren moeten vaak afvlakken richting grijs-aanliggende waarden om door AAA te komen, en dat is precies waarom veel commerciële producten op AA stoppen.
Wat is APCA en is dat WCAG 3.0?
APCA (Advanced Perceptual Contrast Algorithm), ontworpen door Andrew Somers / Myndex, is een kandidaat-algoritme onder het WCAG 3 Silver-project. Het gebruikt polariteitsgevoelige Lc-scores van -108 tot +108 in plaats van symmetrische ratio’s. Per 2026 zit WCAG 3 nog in een vroeg concept en is APCA niet formeel bekrachtigd; WCAG 2.1 / 2.2 AA blijft de regelgevingsstandaard die je vandaag moet halen.
Helpt dark mode bij contrasttoegankelijkheid?
Soms, maar niet automatisch. De symmetrische ratio van WCAG 2 laat dezelfde combinaties slagen in light- en dark mode, maar APCA (dat polariteitsgevoelig is) vlagt bodytekst in dark mode vaak als slechter leesbaar dan hetzelfde hex-paar in light mode. Hertest dark mode altijd tegen zowel WCAG als APCA voordat je het uitlevert; licht-op-donker verliest waargenomen contrast op een manier die de symmetrische ratio niet kan zien.
Waarom zakt mijn merkkleur voor WCAG AA?
Verzadigde kleuren met middenluminantie (de meeste oranjes, gelen, limoengroenen en lichtblauwen) hebben relatieve luminantiewaarden die te dicht bij wit liggen om 4,5:1 te halen. De fix: gebruik de merktint voor accenten en grote koppen, maar pak voor bodytekst een donkerder tint uit dezelfde hue-familie. Gebruik OKLCH om het L-kanaal te verlagen zonder de hue te verschuiven; de Kleurconverter vindt in één stap de dichtstbijzijnde tint die wél slaagt.
Zijn WCAG 2-ratio’s en APCA-scores uitwisselbaar?
Nee. WCAG 2 geeft een symmetrische ratio (1–21); APCA geeft een polariteitsgesigneerde Lc-score (-108 tot +108). De relatie is niet-lineair: een paar dat 4,5:1 scoort in WCAG kan in APCA op Lc 60 of Lc 75 uitkomen, afhankelijk van welke kleur bovenop ligt. Behandel ze als twee onafhankelijke checks, niet als vertalingen van elkaar.
Kan ik kleurcontrast gebruiken voor kleine UI-iconen?
Ja, met een kanttekening. WCAG 2.1 §1.4.11 eist ≥ 3:1 voor UI-componenten en grafische objecten. Voor decoratieve iconen gekoppeld aan een zichtbaar tekstlabel versoepelen de contrasteisen, want het label draagt de betekenis. Voor losstaande iconen (bijvoorbeeld een loep zonder label) handhaaf je de volle 3:1 tegen de omliggende achtergrond.
Hoe test ik kleurenblindheid zonder zelf te simuleren?
Gebruik Chrome DevTools → Rendering → “Emulate vision deficiencies” voor protanopia, deuteranopia, tritanopia en achromatopsia. Combineer met de 8-soorten CVD-preview van de Kleurconverter voor de anomale-trichromacy-varianten (deuteranomalie is met 5% van de mannen de meest voorkomende). Leg voor audit-rapportage screenshots vast onder elke simulatie, zodat reviewers de faalmodi inline kunnen zien.
Conclusie
Vijf inzichten dragen de hele gids:
- AA 4,5:1 is de wettelijke ondergrens. Haal het voor alle bodytekst of reken op compliance-herrie.
- AAA 7:1 is voor zorg, onderwijs en overheid. De meeste commerciële merken stoppen bewust bij AA.
- APCA Lc is de echte-leesbaarheid-sanity-check. Draai het parallel met WCAG 2, vooral voor dark mode en verzadigde merkkleuren.
- Kleur is nooit het enige signaal. Koppel elke kleur-cue aan vorm, tekst of patroon; deuteranomalie alleen al raakt 5% van de mannelijke gebruikers.
- OKLCH L is de juiste knop. Zakt een kleur op contrast, verlaag dan L (niet S, niet B) om het te herstellen zonder dat de hue meedrift.
Gooi twee hex-codes in de Kleurconverter om WCAG-ratio, APCA Lc, gamutclassificatie en de 8-soorten CVD-preview naast elkaar te zien. Dat ene scherm vervangt zes losse tools en is de snelste manier om de audits af te ronden die deze gids beschrijft.