Den Accessibility Tree verstehen und debuggen
A11Y
WCAG
Barrierefreiheit · Accessibility Tree · ARIA · WCAG
Den Accessibility Tree verstehen und debuggen
Warum Screenreader nicht das DOM sehen, sondern einen eigenen Baum

Screenreader und andere assistive Technologien lesen niemals direkt das HTML, sondern eine vom Browser berechnete Parallelstruktur namens Accessibility Tree. Wer versteht, wie DOM, semantisches HTML und ARIA-Attribute diesen Baum formen, kann fehlende oder falsche Accessible Names gezielt mit den richtigen Werkzeugen aufspüren und beheben, statt Barrierefreiheit auf gut Glück zu testen.

16 Min. Lesezeit Accessibility Tree · ARIA · Accessible Name Chrome DevTools · VoiceOver · NVDA · axe-core

1. Was der Accessibility Tree ist und warum er zählt

Der Accessibility Tree ist die Struktur, die Screenreader, Braillezeilen und Spracheingabe-Software tatsächlich konsumieren, nicht das HTML und nicht der DOM-Baum. Der Browser berechnet aus dem DOM parallel zum Render-Baum eine weitere Baumstruktur, in der jeder relevante Knoten eine Rolle, einen berechneten Namen, optional eine Beschreibung sowie Zustände wie „ausgewählt“ oder „deaktiviert“ trägt. Diese Struktur wird über plattformspezifische Schnittstellen wie UI Automation unter Windows, AT-SPI unter Linux oder NSAccessibility unter macOS an assistive Technologien weitergereicht.

Diese Unterscheidung ist keine akademische Feinheit, sondern die Ursache vieler Barrierefreiheits-Bugs. Ein Element kann optisch perfekt aussehen und trotzdem im Accessibility Tree als namenloser Knoten ohne Rolle ankommen, etwa ein anklickbares div ohne semantische Auszeichnung. Für sehende Nutzer ist der Button da, für Screenreader-Nutzer existiert er faktisch nicht. Wer Barrierefreiheit ernsthaft testen will, muss deshalb den Baum inspizieren, nicht nur die visuelle Darstellung im Browser.

2. DOM-Baum und Accessibility Tree: zwei parallele Strukturen

Der DOM-Baum enthält grundsätzlich jeden Knoten des Dokuments, unabhängig davon, ob er sichtbar, versteckt oder rein dekorativ ist. Der Accessibility Tree ist eine gefilterte und semantisch angereicherte Ableitung davon: rein dekorative Elemente werden entfernt, Textknoten werden nicht als eigene Baumknoten geführt, sondern fließen als berechneter Name in ihren Elternknoten ein, und Elemente mit aria-hidden="true", display: none oder visibility: hidden tauchen im Baum überhaupt nicht auf, obwohl sie im DOM weiterhin existieren.

Diese Reduktion ist beabsichtigt: Screenreader-Nutzer sollen nicht durch jedes dekorative Icon oder jeden Trennstrich navigieren müssen. Problematisch wird es, wenn Entwickler unabsichtlich Inhalte aus dem Baum entfernen, etwa ein informatives Bild mit leerem alt="" auszeichnen, obwohl es Inhalt transportiert. Das folgende Beispiel zeigt, wie DOM und Accessibility Tree für dasselbe Markup auseinanderlaufen.


<!-- The DOM keeps every node - the accessibility tree does not -->
<button class="icon-button">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
    <path d="M10 2a8 8 0 105.3 14L20 20l1.4-1.4-4.7-4.7A8 8 0 0010 2z"/>
  </svg>
  <span class="sr-only">Produkte durchsuchen</span>
</button>

<!-- Purely decorative: pruned entirely from the accessibility tree -->
<img src="divider.png" alt="" role="presentation">

<!-- display:none and visibility:hidden are also pruned from the tree -->
<div class="tooltip" style="display:none;">Nur noch 3 Stueck verfuegbar</div>

<!-- Resulting accessibility tree node for the button above:
     role: "button"
     name: "Produkte durchsuchen"
     (the <svg> subtree does not appear as a child node at all) -->

3. Wie Browser den Accessibility Tree berechnen

Der Browser parst zunächst HTML zu DOM, wendet CSS an, um den Render-Baum zu erzeugen, und leitet parallel dazu aus DOM, CSS und ARIA-Attributen den Accessibility Tree ab. Grundlage dafür sind die Mapping-Spezifikationen HTML-AAM und ARIA, die für jedes native HTML-Element eine implizite Rolle festlegen, etwa role="button" für <button> oder role="navigation" für <nav>. Das role-Attribut kann diese implizite Rolle überschreiben, sofern die ARIA-Spezifikation die Kombination erlaubt.

Der Baum ist keine einmalige Momentaufnahme, sondern wird bei jeder relevanten DOM-, Attribut- oder Sichtbarkeitsänderung neu berechnet, ähnlich wie der Render-Baum bei Style-Änderungen. Das ist besonders für Hyvä-Shops mit Alpine.js relevant: Ein Wechsel von x-show zu x-if verändert nicht nur die Sichtbarkeit, sondern auch, ob der Knoten überhaupt im Accessibility Tree existiert. Dynamische Zustände wie ein sich öffnendes Mini-Cart-Dropdown müssen deshalb konsequent über aria-expanded und tatsächliche DOM-Präsenz statt reiner CSS-Klassen abgebildet werden, damit der Baum den echten Zustand widerspiegelt.

4. Semantisches HTML als Fundament des Baums

Native HTML-Elemente bringen Rolle, Fokussierbarkeit und Tastaturverhalten kostenlos mit. Ein <button> ist im Accessibility Tree automatisch als Knoten mit role="button" fokussierbar und lässt sich per Enter oder Leertaste auslösen, ohne dass eine Zeile ARIA nötig wäre. Ein <div> mit einem onclick-Handler besitzt nichts davon: kein Fokus, keine Tastaturbedienung, keine Rolle außer dem generischen Standardwert. Die erste Regel des ARIA Authoring Practices Guide lautet deshalb sinngemäß: keine ARIA-Rolle ist besser als eine falsch nachgebaute.

Landmark-Elemente wie <nav>, <main>, <header> und <footer> bilden zusätzlich das navigierbare Skelett, mit dem Screenreader-Nutzer per Landmark-Sprung direkt zu Inhaltsbereichen springen, ohne die Seite linear abzuhören. Diese Elemente tragen implizite ARIA-Landmark-Rollen und ersparen explizite Auszeichnung wie role="navigation".


<!-- WRONG: div soup - no node with interactive semantics in the tree -->
<div class="add-to-cart" onclick="addToCart(sku)">
  In den Warenkorb
</div>
<!-- Accessibility tree node: role "generic", not focusable,
     no keyboard activation, no pressed/disabled state exposed -->

<!-- RIGHT: native <button> - full semantics for free -->
<button type="button" class="add-to-cart" onclick="addToCart(sku)">
  In den Warenkorb
</button>
<!-- Accessibility tree node: role "button", name "In den Warenkorb",
     focusable, Enter/Space trigger it, no ARIA required -->

<!-- Landmarks build the skeleton assistive technology users jump between -->
<header>...</header>
<nav aria-label="Hauptnavigation">...</nav>
<main>
  <h1>Produktkatalog</h1>
</main>
<footer>...</footer>

5. ARIA-Attribute und ihre Wirkung auf den Baum

ARIA verändert niemals Fokusreihenfolge, Tastaturverhalten oder visuelles Layout, sondern ausschließlich die Knoten des Accessibility Tree. Das role-Attribut überschreibt die Rolle eines Knotens, aria-label und aria-labelledby setzen den berechneten Namen, aria-describedby setzt die Beschreibung, und Zustandsattribute wie aria-expanded, aria-checked oder aria-selected werden als Properties am jeweiligen Baumknoten exponiert, die assistive Technologie unmittelbar ankündigt. aria-hidden="true" entfernt den kompletten Teilbaum unterhalb eines Elements aus dem Accessibility Tree, unabhängig von dessen visueller Sichtbarkeit.

Genau darin liegt eine häufige Falle: aria-hidden="true" auf einem Container, der ein fokussierbares Kindelement enthält, entfernt zwar die Ankündigung, aber nicht den Tabstopp. Tastaturnutzer landen dann auf einem Element, das der Screenreader komplett ignoriert, ein sogenannter Ghost-Fokus. role="presentation" oder role="none" entfernt nur die Semantik eines einzelnen Elements, lässt dessen Kinder aber im Baum bestehen, ein wichtiger Unterschied zu aria-hidden.


/* Visually hidden but still present in the accessibility tree - this is
   the accessible name source for screen reader users */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* WRONG assumption: CSS generated content is not a reliable accessible
   name source. Support is inconsistent across browsers and screen readers. */
.status-badge::before {
  content: "Neu";
}

/* RIGHT: put the text in the DOM as a real node, hide it visually if needed */
.status-badge .sr-only {
  /* "Neu" as a real text node, always exposed to the accessibility tree */
}

6. Die Accessible-Name-Berechnung im Detail

Die sogenannte Accessible Name and Description Computation ist ein festgelegter Algorithmus der ARIA-Spezifikation und legt eine strikte Prioritätsreihenfolge fest: Zuerst zählt aria-labelledby, danach aria-label, danach native Beschriftungsmechanismen wie ein verknüpftes <label>-Element, alt bei Bildern oder caption bei Tabellen, und erst zuletzt der sichtbare Textinhalt des Elements. Diese Reihenfolge wird in der Praxis häufig missverstanden, etwa wenn ein Entwickler ein aria-label ergänzt, das vom sichtbaren Button-Text abweicht, obwohl der sichtbare Text bereits ausreichend wäre.

Genau das verstößt gegen das WCAG-Kriterium 2.5.3 Label in Name: Bei Spracheingabe-Software wie Dragon NaturallySpeaking sagen Nutzer den sichtbar angezeigten Text, um ein Element zu aktivieren. Weicht der berechnete Accessible Name vom sichtbaren Text ab, funktioniert der Sprachbefehl nicht. Automatisierte Tests können diese Berechnung reproduzieren und als Regressionstest in die CI-Pipeline aufnehmen, statt sich bei jedem Deployment auf manuelle Stichproben zu verlassen.


// Unit test: assert the computed accessible name matches intent
// npm install dom-accessibility-api
import { computeAccessibleName } from 'dom-accessibility-api';

const button = document.querySelector('.icon-button');
const name = computeAccessibleName(button);

if (name.trim() === '') {
  throw new Error('Button has no accessible name - screen readers announce "button" only');
}

console.assert(name === 'Produkte durchsuchen', `Unexpected accessible name: "${name}"`);

// CDP: dump the full accessibility tree for automated regression checks
// (Puppeteer)
const client = await page.target().createCDPSession();
await client.send('Accessibility.enable');
const { nodes } = await client.send('Accessibility.getFullAXTree');
const buttonNode = nodes.find(n => n.name?.value === 'Produkte durchsuchen');

7. Debugging-Tools: DevTools, VoiceOver, NVDA und axe-core

Chrome DevTools zeigt im Elements-Panel unter dem Reiter „Accessibility“ die berechneten Properties eines ausgewählten Knotens: Name, Rolle, Beschreibung und die Quelle, aus der der Name stammt. Der Button „Accessibility Tree anzeigen“ neben dem DOM-Baum stellt den kompletten Baum der aktuellen Seite dar und macht sofort sichtbar, welche Elemente fehlen oder falsch benannt sind. Firefox bietet mit dem Accessibility Inspector ein vergleichbares Werkzeug inklusive Kontrastprüfung, macOS liefert mit dem in Xcode enthaltenen Accessibility Inspector ein systemweites Pendant.

Der Baum allein ersetzt jedoch keinen echten Hörtest: VoiceOver unter macOS (Cmd+F5) und NVDA unter Windows, kostenlos verfügbar, decken AT-spezifische Eigenheiten auf, die reine Tree-Inspektion nicht zeigt, etwa unterschiedliche Ankündigungsreihenfolgen bei verschachtelten Live-Regionen. Für automatisiertes, kontinuierliches Testen integriert man axe-core in die CI-Pipeline, das strukturierte Verstoßberichte inklusive betroffenem HTML-Snippet und Behebungsvorschlag liefert.


{
  "id": "button-name",
  "impact": "critical",
  "description": "Ensures buttons have discernible text",
  "help": "Buttons must have discernible text",
  "nodes": [
    {
      "html": "<button class=\"icon-button\"><svg aria-hidden=\"true\"></svg></button>",
      "target": [".icon-button"],
      "failureSummary": "Fix any of the following: Element does not have inner text that is visible to screen readers; aria-label attribute does not exist or is empty; aria-labelledby attribute does not exist, references elements that do not exist or are empty; Element has no title attribute"
    }
  ]
}

8. Häufige Fehler: fehlende oder falsche Accessible Names

Der häufigste Fehler ist der Icon-Button ohne jeden Text: Ein <button>, dessen einziger Inhalt ein <svg> ist, landet zwar mit korrekter Rolle im Accessibility Tree, aber mit leerem Namen, sodass Screenreader nur „Schaltfläche“ ohne weitere Information ankündigen. Ebenso häufig: informative Bilder mit leerem alt="", das eigentlich nur für rein dekorative Bilder gedacht ist, entfernen den Bildinhalt komplett aus dem Baum, obwohl er für sehende Nutzer sichtbar Information trägt.

Ein dritter wiederkehrender Fehler ist ein aria-label, das mit dem sichtbaren Text nicht übereinstimmt oder ihn widersprüchlich ergänzt, etwa aria-label="Zum Warenkorb hinzufügen" auf einem Button mit sichtbarem Text „Kaufen“. Der vierte Klassiker: fokussierbare interaktive Elemente innerhalb eines mit aria-hidden="true" ausgezeichneten Containers erzeugen unsichtbare Tastatur-Fallen. Die Behebung ist in allen Fällen dieselbe Grundregel: sichtbaren Text als primäre Namensquelle nutzen, aria-label nur als letztes Mittel, und aria-hidden niemals auf Container mit fokussierbarem Inhalt setzen.

9. Accessibility Tree im direkten Vergleich

Die folgenden Muster zeigen denselben Fehlertyp aus unterschiedlichen Blickwinkeln: Ein Element existiert visuell, aber der Accessibility Tree bekommt entweder gar keinen, den falschen oder einen widersprüchlichen Knoten. Die rechte Spalte zeigt jeweils, welchen konkreten Effekt die Korrektur auf den berechneten Baum hat.

Problem Falsch Richtig Effekt auf den Baum
Icon-Button ohne Text <button><svg></svg></button> <button aria-label="Suchen"><svg aria-hidden="true"> Leerer Name wird zu gefülltem Namen
Klickbares Element <div onclick="…"> <button type="button"> role generic wird zu role button, fokussierbar
Bild mit Inhalt <img src="chart.png" alt=""> <img alt="Umsatz Q2 um 12% gestiegen"> Knoten bleibt im Baum, Name transportiert Inhalt
Sichtbarer Text plus aria-label <button aria-label="Warenkorb">Kaufen</button> <button>Kaufen</button> Kein Verstoß gegen Label in Name (WCAG 2.5.3)
Versteckter Fokus aria-hidden auf Container mit Button darin Fokussierbare Kinder aus dem Container entfernen oder tabindex="-1" Kein Ghost-Tabstopp ohne Ankündigung

Auffällig ist, dass keine dieser Korrekturen zusätzliche ARIA-Attribute in großem Umfang erfordert. Meistens genügt es, semantisch korrektes HTML zu verwenden und die vorhandenen Namensquellen konsistent zu halten, statt sie durch ein zusätzliches aria-label zu überschreiben. Der Accessibility Tree wird dadurch nicht komplexer, sondern einfacher zu debuggen.

Mironsoft

Barrierefreiheit, Accessibility Audits und Hyvä-Umsetzung für Magento-Shops

Accessibility Tree eures Shops professionell prüfen lassen?

Wir analysieren den Accessibility Tree eurer Magento- und Hyvä-Templates, finden fehlende oder falsche Accessible Names und setzen semantische sowie ARIA-Korrekturen um, die WCAG-konform und automatisiert testbar sind.

Tree-Audit

DevTools-, VoiceOver- und axe-core-Analyse eurer wichtigsten Templates

Semantik-Refactoring

Div-Soup durch native Elemente ersetzen, ARIA nur wo nötig ergänzen

CI-Integration

axe-core und Accessible-Name-Tests in eure Pipeline integrieren

10. Zusammenfassung

Der Accessibility Tree ist die eigentliche Schnittstelle zwischen Webseite und assistiver Technologie, nicht das HTML und nicht der DOM-Baum. Der Browser leitet ihn parallel zum Render-Baum aus DOM, semantischem HTML und ARIA-Attributen ab und aktualisiert ihn bei jeder relevanten Änderung neu. Native HTML-Elemente liefern Rolle, Fokussierbarkeit und Tastaturverhalten kostenlos, während ARIA gezielt Rollen, Namen, Beschreibungen und Zustände ergänzt, ohne Fokus oder Layout zu beeinflussen. Die Accessible-Name-Berechnung folgt einer festen Priorität von aria-labelledby über aria-label bis zum sichtbaren Textinhalt, deren Missachtung zu leeren oder widersprüchlichen Namen führt.

Fehlende oder falsche Namen sind meist keine exotischen Randfälle, sondern entstehen an denselben wiederkehrenden Stellen: Icon-Buttons ohne Text, informative Bilder mit leerem alt, widersprüchliche aria-label-Werte und fokussierbare Elemente in aria-hidden-Containern. Chrome DevTools, Firefox Accessibility Inspector, echte Screenreader-Tests mit VoiceOver oder NVDA sowie automatisiertes Testen mit axe-core in der CI-Pipeline decken diese Fehler zuverlässig auf, bevor sie in Produktion Nutzer aussperren.

Accessibility Tree verstehen und debuggen, das Wichtigste auf einen Blick

DOM vs. Baum

Screenreader lesen nicht das DOM, sondern den vom Browser berechneten Accessibility Tree mit Rolle, Name und Zuständen.

Accessible-Name-Reihenfolge

aria-labelledby vor aria-label vor nativer Beschriftung vor sichtbarem Text. Reihenfolge bestimmt den finalen Namen.

Semantik zuerst

Native Elemente wie <button> und <nav> liefern Rolle, Fokus und Tastatursteuerung ohne jedes ARIA.

Debugging-Werkzeuge

DevTools Accessibility Pane, VoiceOver, NVDA und axe-core in der CI-Pipeline für automatisierte Regressionstests.

11. FAQ: Den Accessibility Tree verstehen und debuggen

1Was ist der Unterschied zwischen DOM und Accessibility Tree?
Der DOM-Baum enthält jeden Knoten, sichtbar oder nicht. Der Accessibility Tree ist eine gefilterte, semantisch angereicherte Ableitung mit Rolle, Name und Zuständen, die assistive Technologie tatsächlich nutzt.
2Warum sehen Screenreader nicht das, was im HTML steht?
Screenreader greifen auf den Accessibility Tree über UI Automation oder AT-SPI zu, nicht direkt auf HTML. Fehlt ein Knoten im Baum, existiert er für den Screenreader nicht.
3Wie berechnet der Browser den Accessible Name?
Feste Priorität: zuerst aria-labelledby, danach aria-label, danach native Beschriftung wie label oder alt, zuletzt der sichtbare Textinhalt.
4Warum entfernt aria-hidden Elemente nur aus dem Baum?
aria-hidden wirkt nur auf den Accessibility Tree, nicht auf DOM oder Rendering. Das Element bleibt sichtbar, wird aber für assistive Technologie unsichtbar.
5Was passiert bei aria-hidden auf fokussierbaren Elementen?
Ein Ghost-Fokus entsteht: per Tab erreichbar, aber vom Screenreader nicht angekündigt. Fokussierbare Kinder zusätzlich mit tabindex="-1" absichern.
6Wie debugge ich falsche Ankündigungen mit DevTools?
Elements-Panel, Reiter Accessibility zeigt Name, Rolle und Namensquelle. Der Button Accessibility Tree anzeigen visualisiert die komplette Baumstruktur der Seite.
7Ist role="presentation" dasselbe wie aria-hidden?
Nein. role="presentation" entfernt nur die Semantik des einzelnen Elements, Kinder bleiben im Baum. aria-hidden entfernt den kompletten Teilbaum.
8Warum reicht ein Screenreader-Test allein nicht?
Verschiedene Screenreader interpretieren denselben Baum unterschiedlich. Korrekter Baum in DevTools plus Test mit VoiceOver oder NVDA ergibt zusammen ein belastbares Bild.
9Kann ich den Baum automatisiert testen?
Ja. dom-accessibility-api berechnet Namen für Unit-Tests, axe-core prüft gegen WCAG-Regeln, Chrome DevTools Protocol liefert per Puppeteer einen vollständigen Baum-Snapshot.
10Häufigster Fehler bei Icon-Buttons?
Ein Button mit nur einem SVG-Icon ohne aria-label oder sichtbaren Text. Korrekte Rolle, aber leerer Name, Screenreader kündigt nur Schaltfläche an.