Direct naar de inhoud

Ontwikkelaar

Als ontwikkelaar ben je verantwoordelijk voor het technische aspect van een website. Maak toegankelijkheid een vast onderdeel van je ontwikkelproces en documenteer eventuele knelpunten en oplossingen duidelijk.

Afbeeldingen

  • Afbeeldingen van tekst

    Afbeeldingen waar (voornamelijk) tekst op staat, en waar die tekst bedoeld is om informatie over te dragen, noemen we afbeeldingen van tekst. Voor deze afbeeldingen geldt: Als dezelfde weergave ook met alleen echte tekst kan worden gemaakt, gebruik dan geen afbeelding van tekst maar gebruik echte tekst.

    Afbeeldingen van tekst zijn voor sommige mensen niet handig omdat een schermlezer de tekst niet standaard voorleest. Ook kunnen de stijleigenschappen van tekst in een afbeelding niet worden aangepast naar eigen wensen of behoeften van iemand, zoals het vergroten van de lettergrootte of het veranderen van de kleur.

    Open dit onderwerp op een eigen pagina

  • Flitsende content

    Flitsende of knipperende content kan gemakkelijk de aandacht trekken. Dit kan bijvoorbeeld voorkomen in animaties of mediabestanden. Deze content kan een epileptische aanval veroorzaken bij mensen die daar gevoelig voor zijn.

    Flitsende content mag daarom niet meer dan 3 keer per seconde flitsen, tenzij het flitsende gedeelte maar een klein oppervlak van het scherm inneemt.

    Open dit onderwerp op een eigen pagina

  • Tekstalternatief bij een afbeelding

    Afbeeldingen die informatie overdragen noemen we informatieve afbeeldingen. Informatieve afbeeldingen zijn belangrijk voor het begrijpen van een tekst of pagina. Deze afbeeldingen vertellen iets over de inhoud of maken een pagina duidelijker.

    Deze afbeeldingen moeten een tekstalternatief hebben dat nauwkeurig beschrijft of uitlegt wat er op de afbeelding te zien is. Beschrijf dit in een korte, duidelijke zin. Vermijd daarmee te algemene termen en probeer specifiek te zijn over wat de afbeelding weergeeft. Deze tekst moet beschrijvend genoeg zijn, zodat het de afbeelding kan vervangen als je die niet kunt zien.

    Een tekstalternatief voor een <​​img​>-element wordt gegeven met het alt-attribuut.

    In de code ziet dat er zo uit:

    <img src="poes.jpg" alt="Witte poes speelt met een rode bal">

    Open dit onderwerp op een eigen pagina

  • Complexe afbeeldingen

    Complexe afbeeldingen, zoals infographics, grafieken of diagrammen voegen veel informatie toe aan een tekst of pagina. Ze vertellen iets over de inhoud of maken een pagina duidelijker.

    Deze afbeeldingen moeten een tekstalternatief hebben. Omdat er vaak erg veel informatie op de afbeelding staat, is het moeilijk om alles beknopt te beschrijven in een kort tekstalternatief. In dat geval is het nuttig om daarnaast ook een meer uitgebreide beschrijving te geven in de omringende tekst. Een handige manier om de visuele informatie ook in tekst aan te bieden, is bijvoorbeeld door de informatie helemaal uit te schrijven. Als het gaat om een diagram of grafiek, gebruik dan bijvoorbeeld een datatabel.

    In de code ziet dat er zo uit:

    <img src="grafiek.jpg" alt="Verkoopcijfers zijn in 2021 met 18% gestegen">
    <div>
      <p>De groei van maandelijkse verkopen in 2021 tegen 2020 verliep als volgt:</p>
      <ul>
        <li>Januari: +22%</li>
        <li>...

    Je kunt ook een link bij de afbeelding plaatsen die verwijst naar een andere pagina met een uitgebreide beschrijving van de informatie op de afbeelding. Zet deze link direct voor of direct na de afbeelding.

    Open dit onderwerp op een eigen pagina

Bediening

  • Slepen: wat het criterium vraagt

    Slepen vraagt drie dingen tegelijk: precies raken, ingedrukt houden en tegelijk bewegen. Voor wie beeft, met zijn ogen aanwijst of een schakelaar gebruikt zijn dat drie opgaven achter elkaar. Kan een functie alleen met slepen worden bediend, zorg dan dat die ook met losse klikken of tikken werkt.

    Dit criterium is nieuw in WCAG 2.2 en staat op niveau AA.

    Waar het opduikt:

    • Schuifregelaars voor een prijsbereik of het volume.
    • Lijsten die je herschikt door onderdelen te verslepen.
    • Kaarten die je moet verschuiven om een ander gebied te zien.
    • Een carrousel die alleen met vegen te bedienen is.

    Er is een uitzondering als het slepen de handeling zelf is: een handtekening zetten, tekenen, schilderen. Bij twijfel helpt één vraag: is hetzelfde resultaat met knoppen te bereiken? Bij een schuifregelaar wel, bij een handtekening niet.

    Dit criterium gaat over de aanwijzer, niet over het toetsenbord. Dat laatste is 2.1.1. Ook wie een muis of aanraakscherm gebruikt maar niet kan slepen, moet erlangs kunnen. Beide criteria moeten dus kloppen.

    Open dit onderwerp op een eigen pagina

  • Zichtbare focus: de focusring

    Een site heeft lichte en donkere vlakken. Een focusrand van één kleur valt daardoor altijd op één van de twee weg. Zet daarom een lichte ring binnen een donkere: op een donkere knop valt de lichte op, op een lichte knop de donkere.

    In de code ziet dat er zo uit:

    :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
      outline: 2px solid transparent;   /* blijft staan in de hoogcontrastmodus */
      outline-offset: 2px;
      box-shadow:
        0 0 0 2px #FFFFFF,              /* binnenring: licht */
        0 0 0 5px #08251C;              /* buitenring: donker */
      border-radius: 6px;
    }

    De doorzichtige outline lijkt overbodig maar is dat niet. In de hoogcontrastmodus van Windows verwijdert het systeem alle kleuren en schaduwen, waardoor de box-shadow verdwijnt. Een outline blijft wel staan en krijgt dan de systeemkleur.

    Gebruik :focus-visible en niet :focus. Met :focus krijgt ook een bezoeker die met de muis klikt een rand om zijn knop. Met :focus-visible bepaalt de browser het zelf: een rand bij het toetsenbord, geen rand bij de muis.

    Drie oplossingen die niet genoeg zijn:

    • Alleen de kleur van de knop veranderen. Kleurverschil alleen is geen zichtbare focus, en voor wie kleur anders ziet werkt het niet.
    • De rand strak om het onderdeel leggen. Met outline-offset blijft er lucht, waardoor de rand ook op een gekleurde knop opvalt.
    • Een rand dunner dan 2 pixels. Op een vergroot scherm valt die weg tegen de rand van het onderdeel zelf.

    Open dit onderwerp op een eigen pagina

  • Tooltips: er een bouwen die blijft staan

    De eenvoudigste oplossing is geen tooltip bouwen maar de tekst op de pagina zetten. Kan dat niet, dan moeten er drie dingen kloppen.

    Escape sluit de uitleg:

    element.addEventListener('keydown', function (e) {
      if (e.key === 'Escape') { verbergTooltip(); }
    });

    De aanwijzer kan erheen. Laat geen gat tussen het onderdeel en de uitleg: beweegt de aanwijzer over dat gat, dan telt dat als wegwijzen en verdwijnt de uitleg.

    .tooltip {
      margin-block-start: 0;
      padding-block-start: 8px;
      pointer-events: auto;
    }

    En er zit geen tijdklok op. Een bezoeker die langzaam leest is na drie seconden halverwege:

    setTimeout(verbergTooltip, 3000);   /* niet doen */

    Gebruik :focus-visible naast :hover, anders krijgt een bezoeker met een toetsenbord de uitleg nooit te zien. Zet daarnaast aria-describedby op het onderdeel, zodat een schermlezer de uitleg voorleest.

    <button aria-describedby="uitleg-btw">Btw-nummer</button>
    <div id="uitleg-btw" role="tooltip">Je btw-nummer staat op je factuur.</div>

    Open dit onderwerp op een eigen pagina

  • Schermstand: zo test je het

    Zet de automatische schermdraaiing van de telefoon aan, open de site en draai het toestel om. Meer is er niet nodig.

    Waar je op let:

    • Verschijnt er een melding dat je moet draaien? Dan is dat de fout.
    • Blijft alle inhoud zichtbaar en bruikbaar?
    • Gaat het menu nog open, en past het op het scherm?
    • Werkt een formulier nog, inclusief de knop onderaan?
    • Blijf je op dezelfde plek in de pagina, of springt hij naar boven?

    Zonder telefoon kan het ook: maak het browservenster laag en breed, bijvoorbeeld 900 bij 400 pixels. In de ontwikkelaarshulpmiddelen van de browser is ook een toestel te kiezen en te draaien.

    Test niet alleen de homepage. De fout zit vaker in een videospeler, een kaart of een ingesloten formulier van een andere partij — onderdelen die iemand anders heeft gebouwd en die hun eigen aannames hebben over de schermstand.

    Succescriteria
    Wie het raakt
    Hulpmiddelen

    Open dit onderwerp op een eigen pagina

  • Klik annuleren: click en niet mousedown

    Een gewone knop met een click voldoet al aan dit criterium. De browser voert die pas uit als de bezoeker op hetzelfde onderdeel loslaat.

    // goed: wegschuiven voordat je loslaat en er gebeurt niets
    knop.addEventListener('click', verwijder);
    
    // fout: gaat af zodra de knop wordt geraakt
    knop.addEventListener('mousedown', verwijder);
    knop.addEventListener('pointerdown', verwijder);
    knop.addEventListener('touchstart', verwijder);

    De onderste drie worden meestal gebruikt omdat de knop dan sneller aanvoelt. Dat verschil is een paar honderdste seconde, en het kost de bezoeker de mogelijkheid om zich te bedenken.

    Kun je niet om het indrukken heen, geef dan een weg terug. Een melding met “Ongedaan maken” die tien seconden blijft staan is genoeg, en is voor iedereen een verbetering. Zorg wel dat die melding zelf met het toetsenbord bereikbaar is en lang genoeg blijft staan; anders verplaats je het probleem.

    Open dit onderwerp op een eigen pagina

  • Apparaatbewegingen

    Acties die in worden geactiveerd door een apparaat te kantelen of te schudden zijn niet goed toegankelijk voor sommige bezoekers. Bezoekers met een motorische beperking kunnen deze acties bijvoorbeeld onbedoeld uitvoeren. Er zijn ook bezoekers die dit niet, of niet goed, kunnen bedienen omdat het apparaat op een vaste plek is bevestigd aan bijvoorbeeld een rolstoel. Ook het maken van gebaren naar een camera die deze de bewegingen kan interpreteren valt onder bewegingsactivering.

    Laat bezoekers daarom de bewegingsactivering uitschakelen of zorg dat acties die kunnen worden geactiveerd met bewegingsactivering ook te activeren zijn met een alternatieve bediening.

    Thema’s

    Open dit onderwerp op een eigen pagina

  • Sneltoetsen

    Op sommige websites kunnen bezoekers gebruik maken van sneltoetsen. Met sneltoetsen kunnen bezoekers gemakkelijk functies uitvoeren of navigeren naar een pagina. Dit werkt goed voor veel bezoekers die gebruik maken van het toetsenbord maar kunnen conflicteren sommige hulptechnologieën. Hierdoor kunnen sneltoetsen onbedoeld worden geactiveerd. Dit geldt bijvoorbeeld voor bezoekers die gebruik maken van software voor spraakherkenning.

    Zorg daarom dat sneltoetsen die bestaan uit één karakter kunnen worden aangepast, uitgeschakeld of alleen geactiveerd kunnen worden als het onderdeel de toetsenbordfocus heeft.

    Open dit onderwerp op een eigen pagina

  • Schermstand: de vergrendeling eruit

    De fout zit bijna altijd op één van twee plekken. De eerste is een media query die de inhoud verbergt:

    /* verbergt de site in liggende stand — nooit doen */
    @media (orientation: landscape) {
      .inhoud { display: none; }
      .draai-melding { display: block; }
    }

    Gebruik orientation gerust om de indeling aan te passen. Gebruik hem nooit om iets te verbergen.

    De tweede is het manifest of de app-instellingen:

    {
      "orientation": "portrait"
    }

    De melding weghalen is de eerste stap. De tweede is zorgen dat het er liggend ook goed uitziet. In liggende stand is het scherm laag en breed, en dat is dezelfde situatie als bij inzoomen:

    .raster {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    }
    
    .hero { min-block-size: 60vh; }   /* niet: height: 60vh */

    Los je dit goed op, dan is 1.4.10 Reflow Reflow meestal ook meteen in orde. Het is dezelfde oorzaak: onderdelen die hun eigen breedte of hoogte vasthouden.

    Succescriteria
    Wie het raakt
    Hulpmiddelen

    Open dit onderwerp op een eigen pagina

  • Bedekte focus: scroll-margin

    De browser schuift een onderdeel net binnen beeld zodra het de focus krijgt. Hij houdt daarbij geen rekening met een balk die eroverheen ligt, want die kent hij niet. Met scroll-margin geef je die ruimte op.

    :where(a, button, input, select, textarea, summary, [tabindex]) {
      scroll-margin-block-start: 120px;   /* de hoogte van de koptekst */
      scroll-margin-block-end: 90px;      /* wat er onderaan blijft staan */
    }

    Zet de bovenwaarde op de hoogte van de koptekst en de onderwaarde op wat er onderaan blijft staan. Verschilt die hoogte per schermbreedte, zet hem dan in een variabele.

    Dit werkt alleen als de browser moet scrollen. Staat het onderdeel al in beeld en valt er toevallig een chatknop overheen, dan gebeurt er niets. Laat zo’n knop dan wijken zodra er iets de focus heeft, en zorg dat de knop daarna nog bereikbaar blijft.

    body:has(:focus-visible) .chatknop {
      opacity: 0;
      pointer-events: none;
    }

    De eenvoudigste oplossing is een balk die niet meescrolt. Een koptekst die gewoon bovenaan de pagina staat kan per definitie niets bedekken, en kost geen onderhoud.

    Open dit onderwerp op een eigen pagina

  • Klik annuleren: wat het criterium vraagt

    Een klik bestaat uit twee momenten: het indrukken en het loslaten. Reageert een knop al op het indrukken, dan is een vergissing niet meer terug te nemen. Reageert hij op het loslaten, dan kan de bezoeker zijn vinger of muis nog wegschuiven en gebeurt er niets.

    Zorg daarom dat een knop pas reageert bij het loslaten. Kan dat niet, geef dan een manier om de actie ongedaan te maken. Dit criterium staat op niveau A.

    Dit maakt verschil voor:

    • Bezoekers met trillende handen, die zelden meteen goed raken.
    • Bezoekers die de aanwijzer met hun ogen of hun hoofd besturen.
    • Bezoekers die slecht zien en pas bij aanraking merken waar ze zitten.
    • Bezoekers die hun telefoon bedienen terwijl ze bewegen.

    Reageren op het indrukken mag wel als dat bij de handeling hoort. Een pianotoets op een scherm hoort te klinken bij aanraking. Hetzelfde geldt voor slepen en tekenen.

    Het gaat vooral om de knoppen waar een vergissing gevolgen heeft: verwijderen, versturen, betalen en opzeggen.

    Open dit onderwerp op een eigen pagina

  • Grootte van knoppen: zo meet je het

    Hiervoor is geen software nodig die je moet installeren. De browser toont de maat van elk onderdeel.

    Eén knop meten:

    • Klik met de rechtermuisknop op de knop en kies Inspecteren.
    • Beweeg de muis over het onderdeel in de code. De browser tekent het gebied op de pagina en zet de maat erbij, bijvoorbeeld 18 × 18.
    • Is een van beide getallen kleiner dan 24, meet dan de ruimte tot de knop ernaast.

    Een hele pagina in één keer: plak dit in het tabblad Console. Het zet een rode rand om elke knop en link die te klein is.

    document.querySelectorAll('a, button, input, select, summary')
      .forEach(function (el) {
        var r = el.getBoundingClientRect();
        if (r.width < 24 || r.height < 24) {
          el.style.outline = '2px solid red';
          console.log(Math.round(r.width) + '×' + Math.round(r.height), el);
        }
      });

    Het lijstje is een beginpunt en geen oordeel. Een knop van 20 bij 20 met 30 pixels ruimte eromheen voldoet gewoon, en een link in een lopende zin is uitgezonderd. Het script kent dat verschil niet.

    Doe de test ook op een smal scherm. Knoppen die op een breed scherm ruim staan, komen op een telefoon tegen elkaar aan.

    Open dit onderwerp op een eigen pagina

  • Focusvolgorde: de volgorde in je HTML

    Eén regel lost het meeste op: schrijf de HTML in de volgorde waarin de pagina gelezen moet worden, en gebruik CSS alleen om te bepalen wáár iets staat.

    Deze drie eigenschappen verplaatsen het beeld zonder de volgorde te veranderen. Het oog volgt de nieuwe plek, het toetsenbord de oude:

    .blok    { order: -1; }
    .raster  { grid-row: 1; grid-column: 2; }
    .zijbalk { position: absolute; right: 0; }

    Wil je de tekst links en het beeld rechts, zet de tekst dan eerst in de HTML. Op een smal scherm komt alles onder elkaar in die volgorde te staan, en dan klopt het daar ook.

    <div class="tweeluik">
      <div class="tekst">…</div>       <!-- eerst lezen, eerst in de code -->
      <figure class="beeld">…</figure>
    </div>
    
    .tweeluik { display: grid; grid-template-columns: 1fr 1fr; }

    Gebruik geen positieve tabindex. Een getal boven nul zet het onderdeel vooraan in de rij, vóór alles wat geen tabindex heeft. Eén zo’n onderdeel zet de hele volgorde op zijn kop. tabindex="0" en tabindex="-1" zijn wel in orde.

    Let daarnaast op twee plekken waar de volgorde met script wordt bepaald. Een venster dat opengaat hoort de focus mee te nemen en bij het sluiten terug te geven aan de knop waarop is gedrukt. Een menu dat uitklapt hoort zijn onderdelen meteen na de knop te hebben staan, niet onderaan de pagina.

    Open dit onderwerp op een eigen pagina

  • Focusvolgorde: zo test je het

    De focusvolgorde is te toetsen met het toetsenbord en het oog. Er is geen software voor nodig.

    Ga als volgt te werk:

    • Klik bovenaan de pagina, buiten een link of invoerveld.
    • Druk op Tab en volg met je ogen waar de focus heen springt.
    • Teken die route in gedachten na: loopt hij van links naar rechts en van boven naar beneden?

    Springt de focus vooruit en dan weer terug omhoog, dan is de afwijking gevonden. Begin bij formulieren: daar heeft een verkeerde volgorde de meeste gevolgen.

    Drie plekken waar het vaak misgaat:

    • Een venster dat opengaat en de focus achterlaat op de pagina erachter.
    • Een uitklapmenu waarvan de onderdelen onderaan de pagina in de code staan.
    • Een tweeluik met beeld en tekst waarvan de code omgekeerd is.

    Zoek in de bronbestanden daarnaast naar een positieve tabindex. Elke treffer is vrijwel zeker een fout:

    tabindex="1"
    tabindex="2"

    Zoek ook naar order: en flex-direction: row-reverse in het stijlbestand. Dat hoeft geen fout te zijn, maar het is wel de plek waar je moet kijken.

    Open dit onderwerp op een eigen pagina

Formulieren

  • Foutmelding: waar en wat

    Bij formulieren hoort een foutcontrole ingebouwd te zijn. De foutcontrole controleert automatisch of een verplicht onderdeel leeg is gelaten of dat een invoerveld verkeerd is ingevuld. Als er een fout is gevonden, dan moet de foutmelding in tekst worden weergegeven. Deze tekst kan worden aangevuld met andere visuele aanwijzingen, zoals een andere kleur of een icoon.

    Benoem in de tekst van de foutmelding de naam van het veld dat verkeerd is ingevuld en benoem precies wat de fout is. Schrijf dus niet:

    • Dit veld is verplicht.

    Maar schrijf:

    • Het veld ‘Telefoonnummer’ mag niet leeg zijn.

    In de code kan ook worden aangegeven welk veld verkeerd is ingevuld. Gebruik hiervoor het attribuut aria-invalid. Daarnaast hoort de foutmelding in de code aan het bijbehorende invoerveld te worden gekoppeld. Dit voorkomt verwarring bij bezoekers die gebruik maken van hulptechnologieën. Een foutmelding kan op een aantal manieren worden gekoppeld zoals met een aria-describedby-attribuut.

    In de code ziet dat er zo uit:

    <label for="veld1">Telefoonnummer:</label>
    <input type="text" id="veld1" aria-invalid="true" aria-describedby="fout">
    <span id="fout">Het veld &lsquo;Telefoonnummer&rsquo; mag niet leeg zijn.</span>

    Open dit onderwerp op een eigen pagina

  • Doel van een invoerveld

    Vaak moeten in formulieren gegevens worden ingevuld die bij veel andere formulieren ook worden gevraagd. Dit geldt voor veelgevraagde gegevens zoals naam, e-mailadres en telefoonnummer.

    Het doel van een invoerveld kan worden vastgelegd in de code. Hierdoor begrijpen browsers welke gegevens er worden gevraagd. Een browser kan het formulier dan al (deels) automatisch zelf invullen. Dit is handig voor alle bezoekers, maar voor bezoekers met een motorische beperking is dit nog belangrijker. Het invullen van een formulier kan hen veel tijd kosten.

    Gebruik hiervoor het autocomplete-attribuut in de code om het doel van het invoerveld toe te voegen aan het <​input​>-element.

    In de code ziet dat er zo uit:

    <label for="veld1">Naam:</label>
    <input type="text" id="veld1" autocomplete="name">
    
    <label for="veld2">Geboortedatum:</label>
    <input type="text" id="veld2" autocomplete="bday">

    Het W3C heeft een lijst met 53 doelen van invoer die in de code horen vastgelegd te worden. (https://www.w3.org/TR/WCAG21/#input-purposes).

    Open dit onderwerp op een eigen pagina

  • Slepen: wat het criterium vraagt

    Slepen vraagt drie dingen tegelijk: precies raken, ingedrukt houden en tegelijk bewegen. Voor wie beeft, met zijn ogen aanwijst of een schakelaar gebruikt zijn dat drie opgaven achter elkaar. Kan een functie alleen met slepen worden bediend, zorg dan dat die ook met losse klikken of tikken werkt.

    Dit criterium is nieuw in WCAG 2.2 en staat op niveau AA.

    Waar het opduikt:

    • Schuifregelaars voor een prijsbereik of het volume.
    • Lijsten die je herschikt door onderdelen te verslepen.
    • Kaarten die je moet verschuiven om een ander gebied te zien.
    • Een carrousel die alleen met vegen te bedienen is.

    Er is een uitzondering als het slepen de handeling zelf is: een handtekening zetten, tekenen, schilderen. Bij twijfel helpt één vraag: is hetzelfde resultaat met knoppen te bereiken? Bij een schuifregelaar wel, bij een handtekening niet.

    Dit criterium gaat over de aanwijzer, niet over het toetsenbord. Dat laatste is 2.1.1. Ook wie een muis of aanraakscherm gebruikt maar niet kan slepen, moet erlangs kunnen. Beide criteria moeten dus kloppen.

    Open dit onderwerp op een eigen pagina

  • Tooltips: er een bouwen die blijft staan

    De eenvoudigste oplossing is geen tooltip bouwen maar de tekst op de pagina zetten. Kan dat niet, dan moeten er drie dingen kloppen.

    Escape sluit de uitleg:

    element.addEventListener('keydown', function (e) {
      if (e.key === 'Escape') { verbergTooltip(); }
    });

    De aanwijzer kan erheen. Laat geen gat tussen het onderdeel en de uitleg: beweegt de aanwijzer over dat gat, dan telt dat als wegwijzen en verdwijnt de uitleg.

    .tooltip {
      margin-block-start: 0;
      padding-block-start: 8px;
      pointer-events: auto;
    }

    En er zit geen tijdklok op. Een bezoeker die langzaam leest is na drie seconden halverwege:

    setTimeout(verbergTooltip, 3000);   /* niet doen */

    Gebruik :focus-visible naast :hover, anders krijgt een bezoeker met een toetsenbord de uitleg nooit te zien. Zet daarnaast aria-describedby op het onderdeel, zodat een schermlezer de uitleg voorleest.

    <button aria-describedby="uitleg-btw">Btw-nummer</button>
    <div id="uitleg-btw" role="tooltip">Je btw-nummer staat op je factuur.</div>

    Open dit onderwerp op een eigen pagina

  • Bij input: zo test je het

    Met een muis is deze fout nauwelijks te vinden: je klikt, kiest en bent klaar. Met het toetsenbord komt hij meteen boven.

    Ga als volgt te werk:

    • Tab naar een keuzelijst.
    • Ga met de pijltoetsen omlaag door de opties, alsof je aan het kijken bent.
    • Gebeurt er iets? Dan is dat de fout.
    • Doe hetzelfde met vinkjes en keuzerondjes: spatie erop en kijken of de pagina blijft staan.

    Vergeet de tekstvelden niet. Vul een veld in en druk op Tab om verder te gaan. Verandert er dan iets aan de pagina — een blok dat verschijnt, een sprong naar boven — dan valt dat ook onder dit criterium.

    In de code is het ook op te zoeken:

    document.querySelectorAll('[onchange], select, input[type=checkbox], input[type=radio]')
      .forEach(function (el) {
        if (el.getAttribute('onchange')) console.warn('onchange:', el);
      });

    Zoek in de bronbestanden daarnaast naar form.submit() en addEventListener('change'. Niet elke treffer is fout, maar het zijn wel de plekken om te kijken.

    Open dit onderwerp op een eigen pagina

  • Inloggen: de wachtwoordbeheerder

    Wie een wachtwoordbeheerder gebruikt hoeft niets te onthouden en niets over te typen. Daarmee is de eis vervuld, zolang de site die beheerder niet in de weg zit.

    Zet daarom het juiste autocomplete-woord op elk veld:

    <label for="gebruiker">E-mailadres</label>
    <input id="gebruiker" name="gebruiker" type="email"
           autocomplete="username">
    
    <label for="wachtwoord">Wachtwoord</label>
    <input id="wachtwoord" name="wachtwoord" type="password"
           autocomplete="current-password">
    
    <label for="code">Code uit je sms</label>
    <input id="code" name="code" type="text" inputmode="numeric"
           autocomplete="one-time-code">

    De laatste wordt het vaakst vergeten en helpt het meest: met one-time-code biedt de telefoon de code uit de sms zelf aan boven het toetsenbord.

    Drie dingen die je niet moet doen:

    • Plakken blokkeren. Bedoeld tegen slordigheid, werkt alleen tegen wie het goed doet.
    • De code opknippen in losse vakjes. Geen wachtwoordbeheerder komt daar doorheen.
    • Het wachtwoordveld hernoemen om beheerders te misleiden.

    Is een CAPTCHA echt nodig, kies er dan een die op gedrag let in plaats van op een puzzel. Blijft er een puzzel over, zorg dan voor een echt alternatief: een telefoonnummer waar iemand opneemt of een e-mailadres dat gelezen wordt. “Probeer het opnieuw” is geen alternatief.

    Open dit onderwerp op een eigen pagina

  • Focus zet iets in gang

    Laat geen grote gebeurtenis plaatsvinden als een bezoeker een veld invoerveld invult, een selectievakje of keuzerondje aanklikt of een waarde kiest uit een keuzelijst, tenzij de bezoeker vooraf is geïnformeerd. Voor veel bezoekers kan een onverwachte gebeurtenis verwarrend zijn. Bezoekers met een visuele beperking kunnen de wijziging misschien niet zien. Bezoekers die alleen met het toetsenbord navigeren kunnen hierdoor moeite hebben met de bediening van de website. Laat de bezoeker daarom zelf op een knop klikken om de gebeurtenis in gang te zetten.

    Grote gebeurtenissen worden contextwijzigingen genoemd. Contextwijzigingen zijn bijvoorbeeld:

    • het automatisch inzenden van een formulier;
    • het openen van een venster;
    • het veranderen van de focus naar een ander onderdeel.

    Er mag ook geen contextwijziging plaatsvinden door het veranderen van de focus.

    Thema’s
    Succescriteria

    Open dit onderwerp op een eigen pagina

  • Bij input: wat het criterium vraagt

    Het bedienen van een onderdeel mag niet vanzelf de context veranderen: geen nieuwe pagina, geen ander venster en geen verplaatste focus. Tenzij vooraf is aangekondigd dat dat gebeurt. Een keuzelijst die zichzelf verstuurt verandert de pagina terwijl de bezoeker nog aan het kiezen is — wie met de pijltjestoetsen door een lijst met landen gaat, is al weg bij de tweede optie.

    De drie klassiekers:

    • Een keuzelijst die verstuurt. Van land, taal of sortering.
    • Een veld dat de focus doorzet. Vier vakjes voor een pincode, en na elk cijfer springt de focus door. Bij een typefout is er geen weg terug.
    • Een vinkje dat de pagina herlaadt, bijvoorbeeld een filter dat meteen zoekt.

    Wie kijkt, ziet dat de pagina verandert. Wie luistert, hoort een schermlezer opnieuw beginnen zonder te weten waarom. Wie langzaam bedient, raakt in de knel omdat het gebeurt vóór hij klaar is.

    Een filter dat de lijst eronder bijwerkt zonder de pagina te herladen en zonder de focus te verplaatsen is geen contextverandering. Dat is een resultaat. Meld de nieuwe stand wel met role="status".

    Open dit onderwerp op een eigen pagina

  • Inloggen: wat het criterium vraagt

    Bij het inloggen mag geen cognitieve test worden opgelegd: geen puzzel, geen code die onthouden en overgetypt moet worden, en geen vraag naar iets wat de bezoeker uit zijn hoofd moet weten. De inlog is de plek waar iedere gebruiker langs moet; wat daar misgaat maakt de rest van de dienst onbereikbaar.

    Er zijn twee uitwegen. Er mag een alternatief zijn dat de test niet vraagt, of de test mag gaan over het herkennen van objecten of van een plaatje dat de bezoeker zelf heeft aangeleverd. Dit criterium is nieuw in WCAG 2.2 en staat op niveau AA.

    Waar het misgaat:

    • Een CAPTCHA met vervormde letters. Dat is puur een test.
    • Een code uit een sms die overgetypt moet worden in een venster dat de sms bedekt.
    • Zes losse vakjes voor die code, waar geen wachtwoordbeheerder mee overweg kan.
    • Een beveiligingsvraag over een eerste huisdier of de meisjesnaam van een moeder.
    • Plakken blokkeren in het wachtwoordveld.

    Dit is de AA-versie en valt onder de wet. 3.3.9 Toegankelijke authenticatie (uitgebreid) is de AAA-versie en laat die uitwegen niet toe: daar mag ook een plaatjespuzzel niet.

    Open dit onderwerp op een eigen pagina

  • Inloggen: zo test je het

    Deze test duurt vijf minuten en gaat met een eigen account.

    Ga als volgt te werk:

    • Zet het wachtwoord in een wachtwoordbeheerder.
    • Log uit en weer in. Vult de beheerder beide velden?
    • Komt er een tweede stap? Is die code te plakken, of wordt hij aangeboden?
    • Noteer alles wat met het hoofd of de vingers moest gebeuren.

    Waar je op let:

    • Losse vakjes voor de code. Probeer te plakken — lukt het?
    • Een CAPTCHA in welke vorm dan ook.
    • Een beveiligingsvraag.
    • Een tijdslimiet die niet gehaald wordt bij langzaam typen.
    • Een venster dat de sms bedekt, zodat de code niet te lezen is.

    De controle in de code:

    document.querySelectorAll('input').forEach(function (el) {
      console.log(el.type, '·', el.autocomplete || 'GEEN AUTOCOMPLETE', '·', el.name);
    });

    Staat er bij het wachtwoordveld geen current-password en bij het codeveld geen one-time-code, dan is duidelijk waar te beginnen.

    Open dit onderwerp op een eigen pagina

  • Overbodige invoer: zo test je het

    Dit is een test met pen en papier. Er is geen software voor nodig, en juist daarom wordt hij zelden gedaan.

    Ga als volgt te werk:

    • Begin bij het begin van een proces met meerdere stappen: een bestelling, een aanvraag, een aanmelding.
    • Schrijf bij elke stap op wélke gegevens er gevraagd worden. Niet wat je invult, maar wat er gevraagd wordt.
    • Loop het lijstje na. Staat er iets twee keer op?

    Staat er iets twee keer, dan is dat een afwijking — tenzij het een wachtwoord is of iets wat echt veranderd kan zijn.

    Waar het meestal zit:

    • Factuuradres en afleveradres.
    • E-mailadres bij het aanmaken van een account en daarna nog eens bij het bestellen.
    • Een naam bovenaan een formulier en nog eens bij de ondertekening.
    • Een klantnummer dat in stap 1 wordt ingevoerd en in stap 3 opnieuw.

    Doe daarna de test die verder gaat: vul het formulier één keer verkeerd in en verstuur. Staat alles wat wél goed was ingevuld er nog? Zo niet, dan wordt niet twee keer hetzelfde gevraagd maar alles opnieuw — precies op het moment dat de bezoeker toch al iets fout deed.

    Open dit onderwerp op een eigen pagina

  • Statusberichten

    Veranderingen in de inhoud van een pagina worden aangegeven met een statusbericht. Een statusbericht voegt nieuwe informatie toe aan de pagina. Het geeft de bezoeker bijvoorbeeld informatie over de resultaten van een actie, over de voortgang van een laadtijd of een waarschuwing over eventuele fouten in een formulier. Deze informatie is belangrijk voor iedereen. Deze informatie moet dus ook beschikbaar worden gemaakt voor een bezoeker die gebruik maakt van hulptechnologieën.

    Hulptechnologie synchroniseert continu met het DOM en merkt de wijziging dus wel op, maar de bezoeker die hiervan gebruik maakt wordt er nietover geïnformeerd. Met het attribuut aria-live wordt een blok een live region. Deze informatie moeten in de code worden opgemaakt zodat ze de aandacht krijgen van hulptechnologieën op een manier die de bezoeker niet onnodig onderbreekt.

    • Bij succes of informatie over voortgang wordt dit gedaan met ARIA role="status" of aria-live="polite".
    • Bij waarschuwing wordt dit gedaan met ARIA role="alert" of aria-live="assertive".
    <div role="status">
      <p>Je instellingen zijn opgeslagen.</p>
    </div>

    Standaard zal hulptechnologie alleen de gewijzigde tekst voorlezen. Als toch het hele blok moet worden voorlezen, voeg dan aria-atomic=”true” toe.

    Een bezoeker heeft geen controle over de uitgesproken informatie. Als een bezoeker (per ongeluk) een toets aanraakt, wordt de aankondiging onderbroken en is er geen manier om de informatie opnieuw te beluisteren.

    Thema’s
    Succescriteria

    Open dit onderwerp op een eigen pagina

  • Focusvolgorde: de volgorde in je HTML

    Eén regel lost het meeste op: schrijf de HTML in de volgorde waarin de pagina gelezen moet worden, en gebruik CSS alleen om te bepalen wáár iets staat.

    Deze drie eigenschappen verplaatsen het beeld zonder de volgorde te veranderen. Het oog volgt de nieuwe plek, het toetsenbord de oude:

    .blok    { order: -1; }
    .raster  { grid-row: 1; grid-column: 2; }
    .zijbalk { position: absolute; right: 0; }

    Wil je de tekst links en het beeld rechts, zet de tekst dan eerst in de HTML. Op een smal scherm komt alles onder elkaar in die volgorde te staan, en dan klopt het daar ook.

    <div class="tweeluik">
      <div class="tekst">…</div>       <!-- eerst lezen, eerst in de code -->
      <figure class="beeld">…</figure>
    </div>
    
    .tweeluik { display: grid; grid-template-columns: 1fr 1fr; }

    Gebruik geen positieve tabindex. Een getal boven nul zet het onderdeel vooraan in de rij, vóór alles wat geen tabindex heeft. Eén zo’n onderdeel zet de hele volgorde op zijn kop. tabindex="0" en tabindex="-1" zijn wel in orde.

    Let daarnaast op twee plekken waar de volgorde met script wordt bepaald. Een venster dat opengaat hoort de focus mee te nemen en bij het sluiten terug te geven aan de knop waarop is gedrukt. Een menu dat uitklapt hoort zijn onderdelen meteen na de knop te hebben staan, niet onderaan de pagina.

    Open dit onderwerp op een eigen pagina

  • Focusvolgorde: zo test je het

    De focusvolgorde is te toetsen met het toetsenbord en het oog. Er is geen software voor nodig.

    Ga als volgt te werk:

    • Klik bovenaan de pagina, buiten een link of invoerveld.
    • Druk op Tab en volg met je ogen waar de focus heen springt.
    • Teken die route in gedachten na: loopt hij van links naar rechts en van boven naar beneden?

    Springt de focus vooruit en dan weer terug omhoog, dan is de afwijking gevonden. Begin bij formulieren: daar heeft een verkeerde volgorde de meeste gevolgen.

    Drie plekken waar het vaak misgaat:

    • Een venster dat opengaat en de focus achterlaat op de pagina erachter.
    • Een uitklapmenu waarvan de onderdelen onderaan de pagina in de code staan.
    • Een tweeluik met beeld en tekst waarvan de code omgekeerd is.

    Zoek in de bronbestanden daarnaast naar een positieve tabindex. Elke treffer is vrijwel zeker een fout:

    tabindex="1"
    tabindex="2"

    Zoek ook naar order: en flex-direction: row-reverse in het stijlbestand. Dat hoeft geen fout te zijn, maar het is wel de plek waar je moet kijken.

    Open dit onderwerp op een eigen pagina

Media

Navigatie

  • Consistente hulp: als sjabloononderdeel

    De oplossing is een afspraak en geen techniek. Kies één plek voor de hulp en wijk daar niet van af.

    Bouw het als één sjabloononderdeel en zet dat op elke pagina neer. Dan kán het niet verspringen, want er is maar één plek waar het vandaan komt:

    <!-- in de voettekst, op elke pagina, in deze volgorde -->
    <h2>Contact</h2>
    <dl>
      <dt>E-mail</dt><dd><a href="mailto:info@voorbeeld.nl">info@voorbeeld.nl</a></dd>
      <dt>Telefoon</dt><dd><a href="tel:+31000000000">000 – 00 00 000</a></dd>
    </dl>
    <p><a href="/contact/">Bezoek de contactpagina</a></p>

    Een chatknop rechtsonder mag, zolang hij op elke pagina rechtsonder staat. Verspringt hij naar linksonder op de bestelpagina omdat daar een knop in de weg zat, dan voldoet de site niet meer.

    Let erop dat de hulp niet over de inhoud valt als iemand inzoomt. Dat raakt 1.4.10 Reflow en 2.4.11.

    Open dit onderwerp op een eigen pagina

  • Vaste namen: wat het criterium vraagt

    Onderdelen die hetzelfde doen horen overal dezelfde naam te krijgen. Dat geldt voor de zichtbare tekst en voor het alternatief van een pictogram. Heet dezelfde knop op de ene pagina “Zoeken”, op de andere “Zoek”, en staat er elders alleen een vergrootglas zonder tekst, dan is dat voor wie kijkt één ding en voor wie luistert drie.

    Waar het vaak misgaat:

    • Een pictogram zonder tekst, met per pagina een ander alternatief: “zoeken”, “zoek”, “vergrootglas”.
    • Downloadlinks: “Download pdf”, “Pdf downloaden”, “Bekijk het rapport” — voor hetzelfde bestand.
    • De knop die een formulier verstuurt: “Versturen”, “Verzenden”, “Aanvragen”, “Ok”.
    • Een sluitkruisje dat de ene keer “Sluiten” heet en de andere keer “Annuleren”.

    Dit telt het zwaarst bij spraakbediening. Wie zijn computer met zijn stem bedient zegt “klik Zoeken”. Heet de knop op die pagina “Zoek”, dan gebeurt er niets.

    Dezelfde naam voor twee dingen die iets anders doen is de omgekeerde fout. Twee links die allebei “Lees meer” heten maar naar verschillende pagina’s gaan, botsen met 2.4.4.

    Open dit onderwerp op een eigen pagina

  • Paginatitel

    Webpagina’s moeten een titel hebben die het onderwerp of doel van de pagina beschrijft. Met een goede paginatitel kunnen gebruikers een pagina gemakkelijk terugvinden als er bijvoorbeeld meerdere tabbladen open staan.

    De paginatitel wordt ook gebruikt door mensen die een schermlezer gebruiken om snel een idee van de inhoud van de pagina te krijgen.

    Een paginatitel voor een webpagina wordt gegeven met het <​​title>-element in het <​​head>-element. In het <​​title>-element moet altijd tekst staan.

    In de code ziet dat er zo uit:

    <html lang="nl">
      <head>
        <title>WCAG.nl - Digitale toegankelijkheid voor iedereen</title>
        ...

    Open dit onderwerp op een eigen pagina

  • Bedekte focus: scroll-margin

    De browser schuift een onderdeel net binnen beeld zodra het de focus krijgt. Hij houdt daarbij geen rekening met een balk die eroverheen ligt, want die kent hij niet. Met scroll-margin geef je die ruimte op.

    :where(a, button, input, select, textarea, summary, [tabindex]) {
      scroll-margin-block-start: 120px;   /* de hoogte van de koptekst */
      scroll-margin-block-end: 90px;      /* wat er onderaan blijft staan */
    }

    Zet de bovenwaarde op de hoogte van de koptekst en de onderwaarde op wat er onderaan blijft staan. Verschilt die hoogte per schermbreedte, zet hem dan in een variabele.

    Dit werkt alleen als de browser moet scrollen. Staat het onderdeel al in beeld en valt er toevallig een chatknop overheen, dan gebeurt er niets. Laat zo’n knop dan wijken zodra er iets de focus heeft, en zorg dat de knop daarna nog bereikbaar blijft.

    body:has(:focus-visible) .chatknop {
      opacity: 0;
      pointer-events: none;
    }

    De eenvoudigste oplossing is een balk die niet meescrolt. Een koptekst die gewoon bovenaan de pagina staat kan per definitie niets bedekken, en kost geen onderhoud.

    Open dit onderwerp op een eigen pagina

  • Vaste namen: de namen vastleggen

    Dit is geen technisch probleem. Het ontstaat doordat verschillende mensen op verschillende momenten een knop een naam geven. De oplossing is een afspraak.

    Maak een lijst met de tien tot twintig onderdelen die overal terugkomen, en spreek per stuk één naam af:

    Zoeken            (niet: Zoek, Vind, Search)
    Versturen         (niet: Verzenden, Ok, Aanvragen)
    Sluiten           (niet: Annuleren, Terug, X)
    Download pdf      (niet: Pdf downloaden, Bekijk pdf)
    Neem contact op   (niet: Contact, Mail ons)

    Een pictogram zonder tekst heeft een naam nodig die niet zichtbaar is. Gebruik overal dezelfde:

    <button aria-label="Zoeken">
      <svg aria-hidden="true">…</svg>
    </button>

    Staat er wel tekst naast het pictogram, dan is die tekst de naam. Zet het pictogram dan op aria-hidden, anders wordt de naam twee keer voorgelezen.

    Let op de vertaling van je thema. Knoppen die uit WordPress of een plugin komen — “Lees verder”, “Vorige”, “Zoeken” — hebben hun eigen vertaling, en die kan afwijken van wat er elders op de site staat. Dat is een van de vaakst gemiste oorzaken van deze fout.

    Open dit onderwerp op een eigen pagina

  • Vaste volgorde op elke pagina

    Navigatiemenu’s en onderdelen die op meerdere webpagina’s voorkomen, moeten telkens in dezelfde volgorde worden geplaatst. Zorg dat deze volgorde zowel in de vormgeving als in de code hetzelfde is.

    Een consistente navigatie- en paginastructuur maakt het voor iedereen makkelijker om te navigeren door de website en informatie op een pagina te vinden. Ook bezoekers die gebruik maken van schermlezers kunnen hierdoor sneller en efficiënter hun weg vinden.

    Open dit onderwerp op een eigen pagina

Ontwerp

  • Leesvolgorde: CSS bepaalt de plek

    De regel is kort: zet in de HTML wat eerst gelezen moet worden, en gebruik CSS om te bepalen wáár het staat.

    Deze drie eigenschappen verplaatsen het beeld zonder de volgorde te veranderen. Ze zijn alle drie nuttig, en worden pas een probleem zodra ze de leesvolgorde omdraaien:

    .blok  { order: -1; }
    .kaart { grid-row: 1; }
    .zij   { position: absolute; top: 0; }

    Gebruik een tabel nooit als indeling. Een tabel wordt cel voor cel gelezen, rij voor rij. Staan er onderdelen naast elkaar in, dan hoort de bezoeker die volgorde ook. Voor een indeling gebruik je grid of flex.

    Let ook op CSS-kolommen. Die lezen van boven naar beneden per kolom, niet van links naar rechts. Dat is precies wat je wilt bij lopende tekst, en precies wat je niet wilt bij een lijst met stappen:

    .tekst { columns: 2; }

    De veilige gewoonte is om eerst zonder opmaak te bouwen. Lees de pagina van boven naar beneden; klopt het verhaal, dan mag de opmaak erop.

    Open dit onderwerp op een eigen pagina

  • Zichtbare focus: de focusring

    Een site heeft lichte en donkere vlakken. Een focusrand van één kleur valt daardoor altijd op één van de twee weg. Zet daarom een lichte ring binnen een donkere: op een donkere knop valt de lichte op, op een lichte knop de donkere.

    In de code ziet dat er zo uit:

    :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
      outline: 2px solid transparent;   /* blijft staan in de hoogcontrastmodus */
      outline-offset: 2px;
      box-shadow:
        0 0 0 2px #FFFFFF,              /* binnenring: licht */
        0 0 0 5px #08251C;              /* buitenring: donker */
      border-radius: 6px;
    }

    De doorzichtige outline lijkt overbodig maar is dat niet. In de hoogcontrastmodus van Windows verwijdert het systeem alle kleuren en schaduwen, waardoor de box-shadow verdwijnt. Een outline blijft wel staan en krijgt dan de systeemkleur.

    Gebruik :focus-visible en niet :focus. Met :focus krijgt ook een bezoeker die met de muis klikt een rand om zijn knop. Met :focus-visible bepaalt de browser het zelf: een rand bij het toetsenbord, geen rand bij de muis.

    Drie oplossingen die niet genoeg zijn:

    • Alleen de kleur van de knop veranderen. Kleurverschil alleen is geen zichtbare focus, en voor wie kleur anders ziet werkt het niet.
    • De rand strak om het onderdeel leggen. Met outline-offset blijft er lucht, waardoor de rand ook op een gekleurde knop opvalt.
    • Een rand dunner dan 2 pixels. Op een vergroot scherm valt die weg tegen de rand van het onderdeel zelf.

    Open dit onderwerp op een eigen pagina

  • Schermstand: zo test je het

    Zet de automatische schermdraaiing van de telefoon aan, open de site en draai het toestel om. Meer is er niet nodig.

    Waar je op let:

    • Verschijnt er een melding dat je moet draaien? Dan is dat de fout.
    • Blijft alle inhoud zichtbaar en bruikbaar?
    • Gaat het menu nog open, en past het op het scherm?
    • Werkt een formulier nog, inclusief de knop onderaan?
    • Blijf je op dezelfde plek in de pagina, of springt hij naar boven?

    Zonder telefoon kan het ook: maak het browservenster laag en breed, bijvoorbeeld 900 bij 400 pixels. In de ontwikkelaarshulpmiddelen van de browser is ook een toestel te kiezen en te draaien.

    Test niet alleen de homepage. De fout zit vaker in een videospeler, een kaart of een ingesloten formulier van een andere partij — onderdelen die iemand anders heeft gebouwd en die hun eigen aannames hebben over de schermstand.

    Succescriteria
    Wie het raakt
    Hulpmiddelen

    Open dit onderwerp op een eigen pagina

  • Vergroten: rem en em

    Zoomen werkt in elke browser, ook als maten in pixels zijn opgeschreven. De instelling voor de standaard tekstgrootte werkt echter alleen met relatieve eenheden — en dat is de instelling die bezoekers één keer aanzetten en daarna vergeten.

    /* volgt de instelling van de bezoeker niet */
    body { font-size: 16px; }
    
    /* volgt hem wel */
    body { font-size: 1rem; }
    h2   { font-size: 1.6rem; }

    Laat ook maten meegroeien met de tekst. Gebruik een minimumhoogte in plaats van een vaste hoogte, en geef de leesbreedte op in tekens:

    .knop {
      padding: 0.7em 1.4em;
      min-block-size: 2.75rem;   /* geen height */
    }
    
    p { max-inline-size: 68ch; }

    em rekent met de tekstgrootte van het onderdeel zelf, rem met die van de pagina. Voor ruimte binnen een knop is em handig, voor alles daarbuiten rem.

    Zet de zoomfunctie nooit uit. Deze regel staat nog in sjablonen van jaren geleden: <meta name="viewport" content="width=device-width, maximum-scale=1, user-scalable=no">. Haal alles achter width=device-width, initial-scale=1 weg.

    Thema’s
    Wie het raakt
    Hulpmiddelen

    Open dit onderwerp op een eigen pagina

  • Schermstand: de vergrendeling eruit

    De fout zit bijna altijd op één van twee plekken. De eerste is een media query die de inhoud verbergt:

    /* verbergt de site in liggende stand — nooit doen */
    @media (orientation: landscape) {
      .inhoud { display: none; }
      .draai-melding { display: block; }
    }

    Gebruik orientation gerust om de indeling aan te passen. Gebruik hem nooit om iets te verbergen.

    De tweede is het manifest of de app-instellingen:

    {
      "orientation": "portrait"
    }

    De melding weghalen is de eerste stap. De tweede is zorgen dat het er liggend ook goed uitziet. In liggende stand is het scherm laag en breed, en dat is dezelfde situatie als bij inzoomen:

    .raster {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    }
    
    .hero { min-block-size: 60vh; }   /* niet: height: 60vh */

    Los je dit goed op, dan is 1.4.10 Reflow Reflow meestal ook meteen in orde. Het is dezelfde oorzaak: onderdelen die hun eigen breedte of hoogte vasthouden.

    Succescriteria
    Wie het raakt
    Hulpmiddelen

    Open dit onderwerp op een eigen pagina

  • Leesvolgorde: zo test je het

    Voor deze test is geen schermlezer nodig. Zet de opmaak uit en lees wat er staat.

    Plak dit in de console van de browser. Alle stijlen gaan uit en de pagina komt in de volgorde van de code te staan:

    document.querySelectorAll('style, link[rel=stylesheet]')
      .forEach(function (el) { el.disabled = true; });

    Waar je op let:

    • Lees van boven naar beneden. Klopt de volgorde met wat je gewend bent?
    • Staan koppen boven de tekst waar ze bij horen?
    • Komt bij een kaart eerst de naam en dan de prijs, of andersom?
    • Staat een bijschrift onder de juiste afbeelding?
    • Komt het menu vóór de inhoud, en de voettekst erna?

    De tweede test is het venster versmallen tot 320 pixels. Alles komt dan onder elkaar te staan, in de volgorde van de code. Springt er iets naar een onverwachte plek, dan is de fout gevonden — en meteen ook een afwijking op 1.4.10.

    Ververs de pagina om de stijlen terug te krijgen.

    Open dit onderwerp op een eigen pagina

  • Grootte van knoppen: zo meet je het

    Hiervoor is geen software nodig die je moet installeren. De browser toont de maat van elk onderdeel.

    Eén knop meten:

    • Klik met de rechtermuisknop op de knop en kies Inspecteren.
    • Beweeg de muis over het onderdeel in de code. De browser tekent het gebied op de pagina en zet de maat erbij, bijvoorbeeld 18 × 18.
    • Is een van beide getallen kleiner dan 24, meet dan de ruimte tot de knop ernaast.

    Een hele pagina in één keer: plak dit in het tabblad Console. Het zet een rode rand om elke knop en link die te klein is.

    document.querySelectorAll('a, button, input, select, summary')
      .forEach(function (el) {
        var r = el.getBoundingClientRect();
        if (r.width < 24 || r.height < 24) {
          el.style.outline = '2px solid red';
          console.log(Math.round(r.width) + '×' + Math.round(r.height), el);
        }
      });

    Het lijstje is een beginpunt en geen oordeel. Een knop van 20 bij 20 met 30 pixels ruimte eromheen voldoet gewoon, en een link in een lopende zin is uitgezonderd. Het script kent dat verschil niet.

    Doe de test ook op een smal scherm. Knoppen die op een breed scherm ruim staan, komen op een telefoon tegen elkaar aan.

    Open dit onderwerp op een eigen pagina

  • Vaste volgorde op elke pagina

    Navigatiemenu’s en onderdelen die op meerdere webpagina’s voorkomen, moeten telkens in dezelfde volgorde worden geplaatst. Zorg dat deze volgorde zowel in de vormgeving als in de code hetzelfde is.

    Een consistente navigatie- en paginastructuur maakt het voor iedereen makkelijker om te navigeren door de website en informatie op een pagina te vinden. Ook bezoekers die gebruik maken van schermlezers kunnen hierdoor sneller en efficiënter hun weg vinden.

    Open dit onderwerp op een eigen pagina

Tekst

  • Leesvolgorde: CSS bepaalt de plek

    De regel is kort: zet in de HTML wat eerst gelezen moet worden, en gebruik CSS om te bepalen wáár het staat.

    Deze drie eigenschappen verplaatsen het beeld zonder de volgorde te veranderen. Ze zijn alle drie nuttig, en worden pas een probleem zodra ze de leesvolgorde omdraaien:

    .blok  { order: -1; }
    .kaart { grid-row: 1; }
    .zij   { position: absolute; top: 0; }

    Gebruik een tabel nooit als indeling. Een tabel wordt cel voor cel gelezen, rij voor rij. Staan er onderdelen naast elkaar in, dan hoort de bezoeker die volgorde ook. Voor een indeling gebruik je grid of flex.

    Let ook op CSS-kolommen. Die lezen van boven naar beneden per kolom, niet van links naar rechts. Dat is precies wat je wilt bij lopende tekst, en precies wat je niet wilt bij een lijst met stappen:

    .tekst { columns: 2; }

    De veilige gewoonte is om eerst zonder opmaak te bouwen. Lees de pagina van boven naar beneden; klopt het verhaal, dan mag de opmaak erop.

    Open dit onderwerp op een eigen pagina

  • Vergroten: rem en em

    Zoomen werkt in elke browser, ook als maten in pixels zijn opgeschreven. De instelling voor de standaard tekstgrootte werkt echter alleen met relatieve eenheden — en dat is de instelling die bezoekers één keer aanzetten en daarna vergeten.

    /* volgt de instelling van de bezoeker niet */
    body { font-size: 16px; }
    
    /* volgt hem wel */
    body { font-size: 1rem; }
    h2   { font-size: 1.6rem; }

    Laat ook maten meegroeien met de tekst. Gebruik een minimumhoogte in plaats van een vaste hoogte, en geef de leesbreedte op in tekens:

    .knop {
      padding: 0.7em 1.4em;
      min-block-size: 2.75rem;   /* geen height */
    }
    
    p { max-inline-size: 68ch; }

    em rekent met de tekstgrootte van het onderdeel zelf, rem met die van de pagina. Voor ruimte binnen een knop is em handig, voor alles daarbuiten rem.

    Zet de zoomfunctie nooit uit. Deze regel staat nog in sjablonen van jaren geleden: <meta name="viewport" content="width=device-width, maximum-scale=1, user-scalable=no">. Haal alles achter width=device-width, initial-scale=1 weg.

    Thema’s
    Wie het raakt
    Hulpmiddelen

    Open dit onderwerp op een eigen pagina

  • Taal van een woord of zin

    Voorleessoftware kan tekst omzetten in spraak. Als de taal niet, of op een verkeerde manier, is aangegeven in de code, dan kan de voorleessoftware de tekst niet duidelijk voorlezen.

    Als een zin of paragraaf in de content in een andere taal dan de standaard taal is geschreven, dan moet dit worden aangegeven in de code. Zo kan software de taal van de webpagina bepalen. Deze verplichting geldt alleen voor zinnen en paragrafen, dus niet voor losse woorden.

    Een taalwissel voor onderdelen van een webpagina wordt ingesteld met het lang-attribuut in het element die een andere taal heeft dan de hoofdtaal van de website. Het lang-attribuut kan worden gebruikt op blok-elementen (<​​div​>, <​​p​>, <​​table​>, enz.) maar ook op inline-elementen (<​​span​>, <​​a​>, <​​strong​>, enz.).

    In de code ziet dat er zo uit:

    <p lang="en">The quick brown fox jumps over the lazy dog.</p>
    
    <p lang="en">In Dutch we say <span lang="nl">Pa's wijze lynx bezag vroom het fikse aquaduct</span>.</p>

    Elke taal heeft zijn eigen code. Voor Nederlands is dat ‘nl‘ (lang="nl"), voor Engels ‘en‘ (lang="en"), en voor Duits ‘de‘ (lang="de").

    Er geldt een uitzondering voor eigennamen, technische termen, woorden van een onbepaalde taal, en woorden of uitdrukkingen die deel zijn gaan uitmaken van de volkstaal van de omringende tekst.

    Open dit onderwerp op een eigen pagina

  • Taal van de pagina

    Voorleessoftware kan tekst omzetten in spraak. Als de taal niet, of op een verkeerde manier, is aangegeven in de code, dan kan de voorleessoftware de tekst niet duidelijk voorlezen.

    Stel de standaardtaal van een website in. Dit helpt software om de taal van de content te bepalen.

    De taal van een website wordt ingesteld met het lang-attribuut in het <​​html​>-element.

    In de code ziet dat er zo uit:

    <html lang="nl">
    ...
    </html>

    Elke taal heeft zijn eigen code. Voor Nederlands is dat ‘nl‘ (lang="nl"), voor Engels ‘en‘ (lang="en"), en voor Duits ‘de‘ (lang="de").

    Open dit onderwerp op een eigen pagina

  • Vaste namen: wat het criterium vraagt

    Onderdelen die hetzelfde doen horen overal dezelfde naam te krijgen. Dat geldt voor de zichtbare tekst en voor het alternatief van een pictogram. Heet dezelfde knop op de ene pagina “Zoeken”, op de andere “Zoek”, en staat er elders alleen een vergrootglas zonder tekst, dan is dat voor wie kijkt één ding en voor wie luistert drie.

    Waar het vaak misgaat:

    • Een pictogram zonder tekst, met per pagina een ander alternatief: “zoeken”, “zoek”, “vergrootglas”.
    • Downloadlinks: “Download pdf”, “Pdf downloaden”, “Bekijk het rapport” — voor hetzelfde bestand.
    • De knop die een formulier verstuurt: “Versturen”, “Verzenden”, “Aanvragen”, “Ok”.
    • Een sluitkruisje dat de ene keer “Sluiten” heet en de andere keer “Annuleren”.

    Dit telt het zwaarst bij spraakbediening. Wie zijn computer met zijn stem bedient zegt “klik Zoeken”. Heet de knop op die pagina “Zoek”, dan gebeurt er niets.

    Dezelfde naam voor twee dingen die iets anders doen is de omgekeerde fout. Twee links die allebei “Lees meer” heten maar naar verschillende pagina’s gaan, botsen met 2.4.4.

    Open dit onderwerp op een eigen pagina

  • Paginatitel

    Webpagina’s moeten een titel hebben die het onderwerp of doel van de pagina beschrijft. Met een goede paginatitel kunnen gebruikers een pagina gemakkelijk terugvinden als er bijvoorbeeld meerdere tabbladen open staan.

    De paginatitel wordt ook gebruikt door mensen die een schermlezer gebruiken om snel een idee van de inhoud van de pagina te krijgen.

    Een paginatitel voor een webpagina wordt gegeven met het <​​title>-element in het <​​head>-element. In het <​​title>-element moet altijd tekst staan.

    In de code ziet dat er zo uit:

    <html lang="nl">
      <head>
        <title>WCAG.nl - Digitale toegankelijkheid voor iedereen</title>
        ...

    Open dit onderwerp op een eigen pagina

  • Leesvolgorde: zo test je het

    Voor deze test is geen schermlezer nodig. Zet de opmaak uit en lees wat er staat.

    Plak dit in de console van de browser. Alle stijlen gaan uit en de pagina komt in de volgorde van de code te staan:

    document.querySelectorAll('style, link[rel=stylesheet]')
      .forEach(function (el) { el.disabled = true; });

    Waar je op let:

    • Lees van boven naar beneden. Klopt de volgorde met wat je gewend bent?
    • Staan koppen boven de tekst waar ze bij horen?
    • Komt bij een kaart eerst de naam en dan de prijs, of andersom?
    • Staat een bijschrift onder de juiste afbeelding?
    • Komt het menu vóór de inhoud, en de voettekst erna?

    De tweede test is het venster versmallen tot 320 pixels. Alles komt dan onder elkaar te staan, in de volgorde van de code. Springt er iets naar een onverwachte plek, dan is de fout gevonden — en meteen ook een afwijking op 1.4.10.

    Ververs de pagina om de stijlen terug te krijgen.

    Open dit onderwerp op een eigen pagina

  • Vaste namen: de namen vastleggen

    Dit is geen technisch probleem. Het ontstaat doordat verschillende mensen op verschillende momenten een knop een naam geven. De oplossing is een afspraak.

    Maak een lijst met de tien tot twintig onderdelen die overal terugkomen, en spreek per stuk één naam af:

    Zoeken            (niet: Zoek, Vind, Search)
    Versturen         (niet: Verzenden, Ok, Aanvragen)
    Sluiten           (niet: Annuleren, Terug, X)
    Download pdf      (niet: Pdf downloaden, Bekijk pdf)
    Neem contact op   (niet: Contact, Mail ons)

    Een pictogram zonder tekst heeft een naam nodig die niet zichtbaar is. Gebruik overal dezelfde:

    <button aria-label="Zoeken">
      <svg aria-hidden="true">…</svg>
    </button>

    Staat er wel tekst naast het pictogram, dan is die tekst de naam. Zet het pictogram dan op aria-hidden, anders wordt de naam twee keer voorgelezen.

    Let op de vertaling van je thema. Knoppen die uit WordPress of een plugin komen — “Lees verder”, “Vorige”, “Zoeken” — hebben hun eigen vertaling, en die kan afwijken van wat er elders op de site staat. Dat is een van de vaakst gemiste oorzaken van deze fout.

    Open dit onderwerp op een eigen pagina

Terug naar boven