Betekenisvolle volgorde en schermlezers

De volgorde van content op een webpagina werkt net zoals de volgorde van bladzijden in een boek. Als je de pagina’s door elkaar husselt, snap je het verhaal niet meer. Op een website gebeurt eigenlijk hetzelfde als de volgorde in de code niet klopt. De volgorde van je content in de code bepaalt wat een schermlezer als eerste aankondigt. Klopt die volgorde niet, dan hoor je de content door elkaar.

In dit artikel leg ik uit hoe je zorgt dat de leesvolgorde van je content wél klopt voor iedereen. Dit onderwerp valt onder succescriterium 1.3.2 Betekenisvolle volgorde van de richtlijnen voor toegankelijkheid van webcontent.

Wat betekent dit succescriterium?

Het criterium zegt:

Als de volgorde waarin content wordt gepresenteerd van invloed is op zijn betekenis, kan een correcte leesvolgorde door software bepaald worden.

Dus: als de volgorde van je content ertoe doet, dan moet die volgorde ook in de code kloppen. Een schermlezer (zoals voorleessoftware of brailleleesregel) kan dan dezelfde volgorde presenteren als wat iemand op het scherm ziet. Dit criterium eist dat er ten minste één correcte leesvolgorde door software bepaald kan worden.

Het criterium geldt alleen als de onderlinge volgorde er ook echt toe doet. Een navigatiemenu en een artikel staan los van elkaar, dus daar maakt de onderlinge volgorde niet uit. Maar bij een stappenplan, een tijdlijn of een recept is de volgorde wél belangrijk. Die moet kloppen in de code.

Waarom de codevolgorde alles bepaalt

Een schermlezer leest de content in de volgorde van de HTML-broncode. Niet in de volgorde die je op het scherm ziet. Alles wat je visueel verplaatst met CSS heeft geen effect op wat een schermlezer voorleest.

Dit komt doordat de browser naast de visuele weergave een aparte boomstructuur maakt voor hulptechnologieën: de accessibility tree. Die boom volgt de HTML-volgorde.

Ik zie regelmatig dat een cookiemelding onderaan in de HTML is geplaatst, maar dan met CSS bovenop de pagina gezet. Iemand die kan zien, die ziet dat blok als eerste, maar een schermlezer kondigt het als laatste aan.

Tekst opmaken zonder witruimte

‘Witruimtekarakters’ zoals spaties, tabs en regeleindes zijn bedoeld om woorden van elkaar te scheiden. Niet om tekst visueel op te maken. Een schermlezer interpreteert de witruimte letterlijk. Extra spaties binnen een woord kunnen dat woord opbreken in losse letters. Spaties die je gebruikt om kolommen te maken, worden genegeerd of verkeerd voorgelezen.

Letters uitrekken

Soms wil je een woord breder weergeven voor een decoratief effect. De verleiding is om spaties tussen de letters te typen: “W e l k o m”. Een schermlezer leest dan mogelijk losse letters in plaats van het woord “Welkom”.

Gebruik in plaats daarvan de CSS-eigenschap letter-spacing. Die geeft hetzelfde visuele effect maar een schermlezer leest gewoon het hele woord:

<!-- Slecht voorbeeld -->
<h1>W e l k o m</h1>

<!-- Goed voorbeeld -->
<h1 style="letter-spacing: 0.5em;">Welkom</h1>

Kolommen en tabellen met spaties

Soms gebruiken redacteuren spaties of tabs om tekst op te maken als kolommen of tabellen. Dat werkt alleen visueel. Een schermlezer leest de tekst regel voor regel van links naar rechts en mixt alles door elkaar.

Gebruik voor kolommen CSS flexbox of grid. Gebruik voor tabulaire informatie (data) een echte HTML-tabel met <th>-elementen als tabelkoppen.

Positionering van kolommen

De meeste leesvolgorde-problemen ontstaan bij opmaak in kolommen. CSS heeft veel manieren om content visueel te herschikken, maar geen van die manieren verandert de volgorde voor een schermlezer. Begin daarom altijd met een HTML-volgorde die overeenkomt met de gewenste leesvolgorde. Voeg daarna pas CSS toe voor de visuele weergave.

Flexbox order

De CSS-eigenschap order verandert de visuele positie van flex items, maar schermlezers negeren dat. De flexbox-specificatie waarschuwt hier zelf voor: gebruik order niet als vervanging voor een correcte broncodevolgorde.

Hetzelfde geldt voor flex-direction: row-reverse en column-reverse. Die keren de visuele volgorde om, maar de broncodevolgorde blijft gelijk.

<!-- Slecht voorbeeld: visueel 1-2-3, schermlezer leest 2-3-1 -->
<div style="display: flex;">
  <div style="order: 2;">Stap 2: Meng de ingrediënten</div>
  <div style="order: 3;">Stap 3: Bak het gerecht</div>
  <div style="order: 1;">Stap 1: Verwarm de oven voor</div>
</div>

<!-- Goed voorbeeld: HTML-volgorde is gelijk aan visuele volgorde -->
<div style="display: flex;">
  <div>Stap 1: Verwarm de oven voor</div>
  <div>Stap 2: Meng de ingrediënten</div>
  <div>Stap 3: Bak het gerecht</div>
</div>

CSS Grid

Met grid-row en grid-column plaats je elementen in willekeurige cellen. De broncodevolgorde verandert niet mee. Vooral grid-auto-flow: dense is riskant. Die waarde pakt elementen automatisch in lege cellen en creëert een visuele volgorde die helemaal losstaat van de code.

De CSS Grid-specificatie bevat dezelfde waarschuwing als flexbox: deze eigenschappen zijn geen vervanging voor een correcte broncodevolgorde.

Positionering met absolute en fixed

Elementen met position: absolute of position: fixed worden uit de normale volgorde gehaald. Ze staan visueel ergens op de pagina, maar de schermlezer leest ze gewoon op de plek waar ze in de HTML staan.

De oplossing: zorg dat de HTML-volgorde overeenkomt met wat je visueel wilt tonen:

<!-- Slecht voorbeeld: absolute positionering -->
<div style="position: relative;">
  <span style="position: absolute; left: 0;">Producten</span>
  <span style="position: absolute; left: 200px;">Locaties</span>
  <span style="position: absolute; left: 0; top: 30px;">Telefoons</span>
  <span style="position: absolute; left: 200px; top: 30px;">Zutphen</span>
</div>

<!-- Goed voorbeeld: flexbox -->
<div style="display: flex; gap: 2rem;">
  <div>
    <h2>Producten</h2>
    <ul>
      <li>Telefoons</li>
      <li>Computers</li>
    </ul>
  </div>
  <div>
    <h2>Locaties</h2>
    <ul>
      <li>Zutphen</li>
      <li>Utrecht</li>
    </ul>
  </div>
</div>

Float

Ook float levert problemen op. Om een element aan de rechterkant te plaatsen (naast andere content), moet het gefloate element eerst in de HTML staan. De broncodevolgorde is dan omgekeerd: rechterkolom eerst, linkerkolom daarna. Dat is precies het tegenovergestelde van de visuele leesvolgorde.

Tabellen voor presentatie

Gebruik tabellen alleen voor tabulaire informatie, niet voor de opmaak. Een presentatietabel plaatst de content in een raster. Een schermlezer leest dat raster cel voor cel: rij 1 cel 1, rij 1 cel 2, rij 2 cel 1, enz. Als de visuele opmaak niet aansluit bij die volgorde, gaat de betekenis verloren.

Stel je hebt een presentatietabel met op de eerste rij twee vragen naast elkaar en op de tweede rij de bijbehorende antwoorden. Visueel staat elk antwoord netjes onder zijn vraag. Maar een schermlezer leest cel voor cel, rij voor rij. Die hoort dus waarschijnlijk eerst beide vragen en daarna pas beide antwoorden. De koppeling tussen vraag en antwoord gaat verloren.

<!-- Slecht voorbeeld: presentatietabel voor lay-out -->
<table>
  <tr>
    <td>Wat kost verzending?</td>
    <td>Hoe lang duurt levering?</td>
  </tr>
  <tr>
    <td>Verzending is gratis vanaf 50 euro.</td>
    <td>Levering duurt 2 tot 3 werkdagen.</td>
  </tr>
</table>

<!-- Goed voorbeeld: betekenis zit in de structuur -->
<dl>
  <dt>Wat kost verzending?</dt>
  <dd>Verzending is gratis vanaf 50 euro.</dd>
  <dt>Hoe lang duurt levering?</dt>
  <dd>Levering duurt 2 tot 3 werkdagen.</dd>
</dl>

Gebruik voor pure lay-out, zoals blokken naast elkaar, CSS flexbox of grid en zorg dat de HTML-volgorde klopt. Hoort content inhoudelijk bij elkaar, zoals een vraag en een antwoord? Leg die relatie dan vast met de juiste structuur, bijvoorbeeld een definitielijst. Gaat het wél om data, zoals een prijslijst of rooster? Gebruik dan een echte tabel met <th> voor de tabelkoppen.

Dynamische content

Content die via JavaScript wordt toegevoegd, belandt op de plek in de HTML waar het script het plaatst. Dat is niet per definitie de juiste plek in de leesvolgorde. Voeg dynamische content daarom toe op de plek waar het visueel verschijnt. Bij een knop die content toont, zet je die content direct na de knop in de HTML.

Het verplaatsen van de focus naar nieuwe content en het bereiken ervan met de Tab-toets valt onder succescriterium 2.4.3 Focus volgorde.

Uitvouwbare content

Bij een accordeon, tabpaneel of uitklapmenu hoeft de schermlezer niet automatisch naar de geopende content te springen. Als de content in de HTML direct na de knop staat, is de leesvolgorde al correct. De gebruiker activeert de knop en de content verschijnt op de juiste plek:

<!-- Goed voorbeeld: content staat direct na de knop -->
<button aria-expanded="false" aria-controls="panel-1">
  Meer informatie
</button>
<div id="panel-1" hidden>
  <p>Deze tekst verschijnt na het activeren van de knop.</p>
</div>

Een leesvolgorde-probleem ontstaat pas als de content op een andere plek in de HTML wordt geplaatst dan waar het visueel verschijnt.

Drag-and-drop

Veel drag-and-drop-implementaties veranderen alleen de visuele positie van elementen via CSS. De HTML-volgorde blijft ongewijzigd. Een schermlezer leest de items dan nog steeds in de oorspronkelijke volgorde.

Verplaats bij drag-and-drop altijd de HTML-elementen zelf. Bied ook een alternatief aan voor gebruikers die niet kunnen slepen, zoals knoppen om items omhoog of omlaag te verplaatsen.

Nieuw: reading-flow

Er is een nieuwe CSS-eigenschap in ontwikkeling: reading-flow. Die eigenschap kan straks de lees- en focusvolgorde laten meebewegen met de visuele volgorde.

Browserondersteuning is voorlopig beperkt tot Chromium-browsers. Vertrouw hier dus nog niet op.

Vereisten en aanbevelingen voor een betekenisvolle volgorde

Dit zijn de vereisten en aanbevelingen voor een betekenisvolle volgorde.

WCAG-vereisten

  • Zorg dat de broncodevolgorde een betekenisvolle volgorde heeft als de volgorde van de content de betekenis beïnvloedt.
  • Gebruik geen CSS-positionering, order, flex-direction: *-reverse of willekeurige grid-plaatsing om content in een andere volgorde te tonen dan de broncode.
  • Gebruik geen spaties, tabs of witruimtekarakters om woorden uit te rekken, kolommen te maken of tabellen na te bootsen.
  • Gebruik geen presentatietabellen die bij linearisatie een onlogische volgorde opleveren.

Aanbevolen

  • Begin altijd met goed gestructureerde HTML. Pas daarna CSS toe voor de visuele vormgeving.
  • Gebruik letter-spacing in plaats van spaties tussen letters voor een breed visueel effect.
  • Voeg dynamische content zoals accordeons en tabpanelen toe naast het activerende element in de HTML.
  • Verplaats bij drag-and-drop-functionaliteit altijd de HTML-elementen zelf. Bied ook een toetsenbordalternatief aan.

Gerelateerde succescriteria

Dit artikel behandelt het volgende WCAG-succescriterium 1.3.2 Betekenisvolle volgorde (niveau A) en raakt ook aan 2.4.3 Focus volgorde.

Laatst gewijzigd op

Niek Derksen

Ik ben WCAG-onderzoeker bij WCAG.nl en heb in ruim 8 jaar tijd meer dan 400 toegankelijkheidsonderzoeken uitgevoerd voor Nederlandse overheidsorganisaties en commerciële bedrijven. De inzichten hiervan deel ik op deze website. Ik werk als senior onderzoeker bij WCAG.nl, onderdeel van VoorMeerWaarde.

Vragen of aanvullingen? Laat het weten

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