Hier bij Eleven Ways krijgen we vaak de vraag naar het “correcte, toegankelijke tooltip-patroon”. Het bouwen van toegankelijke tooltips is een mijnenveld — vooral wanneer je rich content en de eigenaardigheden van screen readers toevoegt. Laten we de problemen onderzoeken en op zoek gaan naar een tooltip-patroon dat werkelijk alle behoeften dekt.
TL;DR
- De Standaard: Het
aria-describedby patroon is het beste startpunt voor eenvoudige controls.
- De Problemen:
- NVDA en JAWS negeren tooltips binnen tekstblokken in Browse mode.
- Narrator faalt bij links.
- Tooltips met links zijn functioneel ontoegankelijk voor keyboard users.
- De Aanbeveling: Gebruik standaard tooltips voor eenvoudige UI, (non-)modal dialogs voor complexe content, en toegankelijke footnotes voor tekstdefinities.
Er is geen native tooltip component in HTML, maar we kunnen een functioneel patroon definiëren op basis van veelvoorkomende implementaties en onderzoek. We destilleren dit tot een patroon bestaande uit:
- Een non-modal (niet-blokkerende) overlay.
- Bevat aanvullende informatie over een UI control.
- Blijft standaard verborgen, en verschijnt alleen bij hover of focus van die control.
Een strikte definitie vereist alleen platte, beschrijvende tekst, maar we zien vaak implementaties met formatting of links. Dus laten we onze criteria uitbreiden:
- Kan rich content bevatten.
- Kan links bevatten.
De baseline standaard
Met toegankelijkheidsvereisten in gedachten, biedt de tooltip implementatie van Deque University een uitstekende baseline. Het belangrijkste kenmerk is het gebruik van aria-describedby, een methode die de voorkeur geniet van bijna elke implementatie die streeft naar een toegankelijkheidsstandaard.
Belangrijkste kenmerken van deze implementatie:
- Focusbaar: de tooltip is gekoppeld aan een focusable element, zoals een form field, link of button.
- Doel: het geeft meer informatie over dat element.
- Semantiek: de tooltip wordt aangeroepen door het focusable element via
aria-describedby. Dit zorgt ervoor dat de tooltip wordt gelezen wanneer het element focus krijgt.
- Dit betekent dat de tooltip verborgen kan zijn (met
CSS display:none, visibility:hidden, of het HTML hidden attribuut) en nog steeds wordt gevonden en gelezen door ondersteunende technologie.
- De tooltip heeft een rol nodig; in dit geval
role="tooltip".
- Interactie: het is aanwijsbaar, men kan het aanhouden en men kan het sluiten:
- De pointer kan over de extra content worden bewogen zonder dat deze verdwijnt (aanwijsbaar).
- Blijft op het scherm zolang de trigger focus heeft (aanhouden).
- Kan worden gesloten met de Esc-toets (sluiten) of door de focus te verplaatsen.
- Deque Best Practice: het openhouden van de tooltip gebeurt door een vertraging in het hover-out gedrag te implementeren.
Scenario’s uit de praktijk testen
Om het gedrag van screen readers voor onze standaard te testen, kunnen we de demo pagina van Deque University gebruiken.
Daarnaast hebben we ook onze eigen demo-pagina gemaakt, om deze praktijkvoorbeelden te testen:
- Werkt de tooltip wanneer deze een link bevat?
- Werkt de tooltip wanneer deze wordt gelezen als onderdeel van een blok tekst? We kunnen ons beperken tot buttons en functionele links, omdat die het meest praktisch zinvol zijn.
- Zo ja, wordt het in context gelezen (na het triggerende element)?
We hebben deze getest met NVDA, Narrator, VoiceOver (macOS/iOS), en Android TalkBack.
Uit Webaim Screen Reader User Survey #10 Resultaten (vertaald uit het Engels):
"NVDA is opnieuw de meest gebruikte screen reader met 65,6% van de respondenten, met JAWS op 60.5%. Narrator ... wordt veel gebruikt door 37,3% van de respondenten ... Respondenten met beperkingen (72,4%) gebruikten iOS-apparaten in hogere mate dan degenen zonder beperkingen (56%)".
De resultaten
- Desktop
- VoiceOver (MacOS):
- Focussen op elementen (tab-toets op toetsenbord): Het element wordt benoemd (bijv. ‘link, link 1’, ‘button 1), de tooltip wordt getoond, het label (
aria-label) van de tooltip evenals de tooltip zelf worden gelezen.
- Tekst lezen (gebruikmakend van Interactie en Tekst commando's):
- Selecteer en lees een element met een tooltip: dezelfde resultaten.
- Tekst continu lezen: Wanneer VoiceOver bij de trigger komt, leest het het element voor, opent de tooltip en leest deze.
- JAWS (Windows)
- Focussen op elementen (a.k.a. ‘Form mode’, gebruikmakend van tab-toets op toetsenbord):
- Het element wordt benoemd, de tooltip wordt getoond, het label van de tooltip en tekst wordt gelezen door de screen reader.
- Het benoemt het item (bijv. ‘link, link 1’, ‘button 1) of de naam van het veld (’Last name’).
- Het leest eerst de tooltip
aria-label (’Tooltip : `), gevolgd door de inhoudstekst.
- Tekst lezen (a.k.a. ‘Browse mode’, gebruikmakend van commando's):
- Selecteer en lees elementen: het element en de tooltip worden gelezen, maar niet getoond.
- Tekst continu lezen: de tooltip wordt niet geopend en niet gelezen.
- NVDA (Windows):
- Focussen op elementen (gebruikmakend van tab-toets):
- Leest het element + het label ("tooltip") + de inhoud van de zichtbare tooltip.
- Tekst lezen (a.k.a. ‘Browse mode’, gebruikmakend van pijltjestoetsen):
- Voor losstaande elementen: leest het element, dan (bij de volgende pijl omlaag) de inhoud van de tooltip. Maar zegt het label "tooltip" niet meer.
- Wanneer de tooltip trigger (bijv. als een button) in een paragraaf tekst staat, wordt de tooltip niet voorgelezen.
- Microsoft Narrator (Windows):
- Narrator met Edge leest de tooltips voor de form fields en de buttons, maar niet voor de links.
- Mobile
- TalkBack (Android)
- De tooltip wordt gelezen: eerst het label, gevolgd door de tooltip inhoudstekst.
- Wanneer touch wordt gebruikt om toegang te krijgen tot de elementen in plaats van een toetsenbord, is de tooltip niet zichtbaar bij het focussen op een element.
- iOS VoiceOver (iPhone/iPad)
- Het leest het label van de tooltip, gevolgd door de tooltip inhoudstekst.
- Wanneer touch wordt gebruikt om toegang te krijgen tot de elementen in plaats van een toetsenbord, is de tooltip niet zichtbaar bij het focussen op een element.
De problemen die we tegenkwamen
Onze testen brachten verschillende kritieke gaten aan het licht waar standaard implementaties niet voldoen aan de behoeften van gebruikers:
- NVDA and JAWS browse modes:
- Voor losstaande elementen faalt NVDA om het
aria-label (het "Tooltip:" prefix) aan te kondigen bij het navigeren met pijltjestoetsen.
- Voor beide, NVDA en JAWS, worden tooltips voor elementen die zijn ingebed in tekstblokken helemaal niet in context gelezen.
- Microsoft Narrator: Tooltips op links worden simpelweg niet aangekondigd door Narrator.
- Functionele ontoegankelijkheid: Links die zich binnen tooltips bevinden kunnen niet worden bereikt via keyboard navigatie, wat betekent dat ze niet op die manier geopend kunnen worden.
1. NVDA and JAWS browse modes
Discrepantie tussen NVDA’s Focus en Browse modes kan worden toegeschreven aan inherente verbosity instellingen, zoals Adrian Roselli opmerkt in de reacties van zijn artikel over aria-describedby. Hoewel gebruikers deze instellingen vaak kunnen aanpassen, willen we er zeker van zijn dat tooltips in tekstblokken standaard worden gelezen. We vonden geen succes in het sleutelen aan deze instellingen om het probleem op te lossen.
Geprobeerde workarounds voor NVDA / JAWS
We hebben momenteel geen "schone" fix, omdat onze pogingen steeds meer complexiteit of verwarring toevoegden.
Fixen van het aria-label: Om ervoor te zorgen dat de "Tooltip:" prefix wordt gehoord, kun je een visueel verborgen span toevoegen binnen de tooltip tekst.
De CSS:
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
De JS:
data-tooltip="<span class=\"sr-only\">Tooltip: </span>This is the tooltip content"
Het "Double Duty" Label: Voor triggers binnen tekstblokken was de enige levensvatbare workaround die we vonden, het kapen van het label. We gebruiken de trigger om enerzijds de gebruiker te informeren dat er een tooltip beschikbaar is, maar ook nog steeds om info bij de link te geven. Dit betekent dus dat het onderscheid tussen de Actie (ergens heen navigeren) en de extra Informatie (de tooltip inhoud) mogelijks verloren gaat.
<!-- For a button --> <button aria-label="funambulist - focus or hover to get the definition of 'funambulist'" data-tooltip="This tooltip contains the definition of the word funambulist">funambulist</button>
<!-- For a link --> <a href="https://some-site" aria-label="funambulist - focus or hover to get important information about an article on funambulists" data-tooltip="This tooltip contains important context about a linked article">funambulist</a>
2. Het Narrator probleem
Het falen van links met aria-describedby in Microsoft Narrator blijkt een bug te zijn. Hoewel het attribuut technisch is toegestaan op elk element met een ARIA role, vindt Narrator de beschrijving voor links simpelweg niet.
Als we historische data over aria-describedby by van A11ySupport.io en tests door Adrian Roselli erbij nemen, blijkt ondersteuning voor aria-describedby al lang kapot in Narrator. Hoewel ondersteuning voor buttons uiteindelijk werd opgelost, is dat 4 jaar later voor links nog steeds niet het geval. Maar aangezien Narrator wordt gebruikt door 37,3% van de respondenten, willen we nog steeds die gebruikers ondersteunen.
Geprobeerde workarounds voor Narrator
- Accessibility tree hacks: We hebben getest met gebruikelijke hacks zoals role switching en expliciete
tabindex, maar deze faalden. De voor de hand liggende reden is dat het probleem in de implementatie van Narrator zit (of Microsoft Speech API), niet in de interpretatie van de browser.
- Alternatieve beschrijvingen: Het gebruik van
title of aria-label op de link zelf wordt niet aanbevolen. Screen readers die aria-describedby wel ondersteunen zouden de tekst twee keer lezen, en deze eigenschappen zijn bedoeld om de naam van de link te geven, niet een aanvullende beschrijving.
3. Functionele ontoegankelijkheid
De reden dat links niet bereikt kunnen worden, komt door hoe aria-describedby is geïmplementeerd in browsers. De trigger heeft focus nodig om de beschrijving te laten verschijnen/lezen door screen readers. Zodra die focus weg is (bijv. door deze naar een genest element te verplaatsen), is de verbinding weg. Dat verklaart ook waarom aria-describedby bedoeld is om alleen platte tekst te bevatten.
Technisch gezien, als de tooltip inhoud complex is of semantische elementen bevat, is aria-details een meer geschikt attribuut. Maar aria-details werd niet voorgelezen door onze screen readers, dus het is geen levensvatbare optie.
Een opmerking over markup
In onze tests werd markup in aria-describedby visueel zonder problemen weergegeven. Hoe screen readers omgaan met inline markup (zoals <strong>) of speciale tekens hangt af van de specifieke reader en de individuele verbosity instellingen van de gebruiker. Bijvoorbeeld, NVDA kondigde emoji's standaard aan, terwijl VoiceOver dat niet deed. Bijgevolg behandelen we "markup ondersteuning" als een non-issue.
Tussentijdse conclusie: bouwen aan een alternatief?
Aangezien aria-describedby in verschillende gevallen faalt, kunnen we een tooltip bouwen zonder? Het antwoord is: "Het hangt ervan af van welke criteria je bereid bent los te laten".
Om even te herhalen, we wilden deze oorspronkelijke problemen aanpakken:
- Tooltips moeten werken binnen paragrafen en op functionele links.
- Links binnen tooltips moeten keyboard-toegankelijk zijn.
Terwijl we naar alternatieven kijken, kunnen we ook enkele "nice-to-have" verbeteringen proberen te integreren:
- Het sluiten van een tooltip zou moeten gebeuren wanneer een andere opent om visuele problemen te vermijden.
- Het toevoegen van een Sluiten-knop om de ervaring te verbeteren voor gebruikers die geen nauwkeurige pointer control hebben.
Het non-modal dialog experiment
De oplossing die het meest overeenkomt met dit gedrag is een non-modal dialog. (Let op: "Modal" verwijst naar de staat van het blokkeren van de rest van de pagina, terwijl "Dialog" verwijst naar de component zelf). Echter, dialoogpatronen bieden geen methode voor een screen reader om de informatie voor te lezen wanneer de dialoog opent.
We hebben 2 mogelijke wegen onderzocht om dit op te lossen, maar stuitten op grote obstakels bij beide:
- Live regions: het gebruik van
aria-live is problematisch omdat aankondigingen niet gemakkelijk kunnen worden genegeerd, wat de flow van de gebruiker onderbreekt. Het vereist ook dat de regio aanwezig is in de DOM bij het laden van de pagina om gedetecteerd te worden, wat potentieel weer problemen veroorzaakt met Javascript en populaire frameworks die momenteel erg in trek zijn.
- Focus verplaatsen: Het automatisch verplaatsen van focus naar de tooltip schendt WCAG 2.2 SC 3.2.1: On Focus. Maar zelfs als dat niet zo was, worden we nog steeds geconfronteerd met problemen:
- Focus beheren: dit is technisch complex en gevoelig voor onverwacht gedrag. Bijvoorbeeld: hoe heropen je een dialoog wanneer je deze gesloten hebt? De focus keert terug naar de trigger, maar dat betekent niet dat je de dialoog onmiddellijk opnieuw wilt activeren.
- Aanhoudende Narrator/NVDA Problemen: Zelfs met een gefocuste dialoog faalden Narrator en NVDA om de inhoud in context aan te kondigen bij het scannen van een volledige paragraaf.
Voor de volledigheid hebben we een proof-of-concept gemaakt om het hover-gedrag te testen (in gedachte houdend dat het WCAG 3.2.1 On focus faalt).
Aanbevelingen
Er is geen oplossing die voor iedereen, onder elke omstandigheid, werkt. We moeten kiezen op basis van het specifieke scenario.
Onze eerste aanbeveling is om informatie op een gemakkelijk bereikbare manier nabij het element te plaatsen. Voor invoervelden is het toevoegen van een beschrijving onder het veld en het gebruik van aria-describedby de meest eenvoudige methode.
Voor de meeste scenario's blijft een tooltip gebaseerd op aria-describedby (zoals geïllustreerd door Deque) de beste optie.
- Kanttekening: Neem geen links op binnen de tooltip.
- Kanttekening: Gebruik ze niet in tekstblokken waar ze in context gelezen moeten worden.
Als je ze wel op links wilt gebruiken, zul je moeten wachten tot Microsoft Narrator is gefixt.
Als je wilt helpen om dat vooruit te helpen, dien dan een issue in via de Microsoft Feedback Hub. Hoe meer mensen erover klagen, hoe groter de kans dat we een update krijgen die het probleem oplost.
3. Voor links of complexe markup
Als je tooltip links nodig heeft, moet je een (non-)modal dialog gebruiken die geopend wordt door een klik of Enter-toets.
Als je wilt spelen met een voorbeeld, we hebben hier een demo-pagina voor gemaakt.
Begrijp wel dat dialoogvensters ook hun eigen eigenaardigheden hebben, waar we hier niet op in zullen gaan. Bvb. Adrian Roselli heeft een uitstekend artikel over dialoog focus.
4. Voor definities binnen tekst
Om informatie toe te voegen aan woorden in een paragraaf, raden we toegankelijke footnotes aan. Ons voorkeurspatroon is gebaseerd op onderzoek door Nicki Bright, dat "back links" en visueel verborgen tekst gebruikt voor de duidelijkheid.
Je kunt het uitproberen op onze demo-pagina of neem een kijkje bij dit codevoorbeeld:
<p>
A bit of text that needs a footnote
<a id="footnote-01-link" href="#footnote-01">
<sup>[1] <span class="sr-only">Footnote details</span></sup>
</a>.</p>
<ol>
<li id="footnote-01">
The footnote text goes here
<a href="#footnote-01-link" aria-label="Back to content">↩</a>
</li></ol>
Conclusie
Bij Eleven Ways geloven we dat toegankelijkheid betekent: begrijpen hoe echte mensen omgaan met technologie. Tooltips lijken misschien maar een klein deel van de UI, maar de impact van een kapotte implementatie blokkeert de gebruikers die op deze informatie vertrouwen.
Door het juiste patroon voor de juiste context te kiezen, kunnen we aan een web bouwen dat werkelijk voor iedereen toegankelijk is.
Verder lezen
Voor verder lezen over de fundamenten van toegankelijke tooltips, raden we deze (Engelstalige) artikels aan: