Aktualisiert: März 2026 · Lesezeit: 14 Min.
Als ich vor drei Jahren angefangen habe, Websites mit Screenreader zu testen, war das ein ziemlicher Augenöffner. Wortwörtlich. Ich habe VoiceOver auf meinem Mac eingeschaltet, die Augen geschlossen und versucht, auf der Website eines meiner Kunden einen Termin zu buchen. Nach acht Minuten hatte ich es aufgegeben. Der Screenreader las jedes einzelne Icon als „Bild", die Navigation war ein endloser Strom von „Link Link Link Link", und der Buchungskalender war schlicht nicht bedienbar.
Das war der Moment, in dem ich verstanden habe, warum Barrierefreiheit keine theoretische Übung ist. Seitdem teste ich jede Website, die ich auditiere, mindestens eine Stunde lang nur mit Screenreader. Und ich empfehle jedem Webentwickler dringend, das ebenfalls zu tun.
Ein Screenreader liest nicht den Bildschirm. Das ist ein verbreitetes Missverständnis. Ein Screenreader liest den Accessibility Tree — eine vereinfachte Version des DOM, die der Browser aus dem HTML-Code generiert. Dieser Tree enthält für jedes Element:
Wenn Ihr HTML-Code semantisch korrekt ist, baut der Browser einen guten Accessibility Tree. Wenn Sie alles mit <div> und <span> bauen, sieht der Screenreader — nichts. Oder genauer: Er sieht generischen Text ohne Struktur, ohne Rolle, ohne Kontext.
Screenreader-Nutzer navigieren nicht wie sehende Nutzer. Sie scrollen nicht mit den Augen und scannen die Seite visuell. Stattdessen nutzen sie Landmarks — definierte Bereiche, zu denen sie direkt springen können.
NVDA zum Beispiel bietet die Taste D zum Springen zwischen Landmarks. VoiceOver nutzt den Rotor (Ctrl+Option+U).
<!-- Vorher: Keine Landmarks --> <div class="header">...</div> <div class="sidebar">...</div> <div class="content">...</div> <div class="footer">...</div> <!-- Nachher: Landmarks --> <header> <nav aria-label="Hauptnavigation">...</nav> </header> <aside aria-label="Seitenleiste">...</aside> <main>...</main> <footer> <nav aria-label="Footer-Navigation">...</nav> </footer>
Beachten Sie die aria-label-Attribute bei den <nav>-Elementen. Wenn Sie mehrere Navigationen haben (Hauptnavigation, Footer-Navigation, Breadcrumb), muss jede eindeutig benannt sein. Sonst hört der Nutzer dreimal „Navigation" und weiß nicht, welche welche ist.
WCAG 2.4.1 fordert eine Möglichkeit, wiederkehrende Blöcke zu überspringen. Landmarks sind eine Methode. Skip-Links sind eine andere — und sie sind besonders für Tastaturnutzer hilfreich, die keinen Screenreader verwenden.
<!-- Skip-Link als erstes Element im Body -->
<a href="#main-content" class="skip-link">
Zum Hauptinhalt springen
</a>
<!-- Zielanker -->
<main id="main-content" tabindex="-1">
...
</main>
<style>
.skip-link {
position: absolute;
top: -100%;
left: 0;
background: #1a56db;
color: white;
padding: 0.5rem 1rem;
z-index: 1000;
transition: top 0.1s;
}
.skip-link:focus {
top: 0;
}
</style>
Der Skip-Link ist standardmäßig unsichtbar (via top: -100%), wird aber sichtbar, wenn er per Tab fokussiert wird. Das tabindex="-1" auf dem <main>-Element stellt sicher, dass der Fokus dorthin gesetzt werden kann.
Übrigens: Viele große Websites haben Skip-Links. Google, Amazon, GitHub — probieren Sie es aus. Öffnen Sie eine dieser Seiten und drücken Sie Tab. Sie werden überrascht sein.
Die meisten Screenreader-Nutzer navigieren über Überschriften. NVDA: Taste H für nächste Überschrift, 1-6 für Überschriften eines bestimmten Levels. In der WebAIM Screen Reader User Survey 2024 gaben 67,5 % der Befragten an, dass sie Überschriften als primäre Navigationsmethode nutzen.
Was Screenreader bei schlechter Überschriftenstruktur „sehen":
<!-- Schlecht: Überschriften als Styling-Tool --> <h1>Unser Shop</h1> <h3>Neue Produkte</h3> <!-- H2 übersprungen --> <h5>Sommerkollektion</h5> <!-- H4 übersprungen --> <h2>Kontakt</h2> <!-- Springt zurück --> <!-- Gut: Logische Hierarchie --> <h1>Unser Shop</h1> <h2>Neue Produkte</h2> <h3>Sommerkollektion</h3> <h3>Winterkollektion</h3> <h2>Kontakt</h2>
Faustregel: Die Überschriftenstruktur sollte wie ein Inhaltsverzeichnis funktionieren. Wenn Sie die Überschriften extrahieren, muss der Seiteninhalt allein daraus verständlich sein.
Jedes interaktive Element braucht einen zugänglichen Namen (WCAG 4.1.2). Screenreader lesen diesen Namen vor, um dem Nutzer zu sagen, was das Element tut.
<!-- Problem: Linktext ohne Kontext --> <p>Weitere Informationen zum BFSG finden Sie <a href="/bfsg">hier</a>.</p> <!-- Screenreader: "Link: hier" — wohin? --> <!-- Lösung 1: Beschreibender Linktext --> <p><a href="/bfsg">Weitere Informationen zum BFSG</a></p> <!-- Screenreader: "Link: Weitere Informationen zum BFSG" --> <!-- Lösung 2: aria-label wenn Linktext nicht änderbar --> <p>Weitere Informationen zum BFSG finden Sie <a href="/bfsg" aria-label="Weitere Informationen zum BFSG">hier</a>.</p>
Screenreader-Nutzer können sich alle Links einer Seite als Liste anzeigen lassen (NVDA: Insert+F7). Stellen Sie sich diese Liste vor: „hier, hier, hier, mehr, mehr, klicken Sie hier". Nicht hilfreich. Die Links müssen auch ohne umgebenden Text verständlich sein (WCAG 2.4.4).
Alt-Texte sind nur die Spitze des Eisbergs. Es gibt Bildsituationen, die komplexer sind:
<!-- Kurzer Alt-Text + ausführliche Beschreibung -->
<figure>
<img src="bfsg-timeline.png"
alt="Timeline der BFSG-Umsetzung 2019-2030"
aria-describedby="timeline-desc">
<figcaption id="timeline-desc">
Die Timeline zeigt die wichtigsten Meilensteine:
April 2019 (EAA-Verabschiedung), Juli 2021 (BFSG verabschiedet),
Juni 2025 (Pflichten in Kraft), Juni 2030 (Ende der Übergangsfrist
für Selbstbedienungsterminals).
</figcaption>
</figure>
WCAG 1.4.5 sagt: Verwenden Sie keinen Text in Bildern, wenn es sich mit echtem Text machen lässt. In der Praxis sehe ich das oft bei Bannern, die als Bild eingebunden sind. Der gesamte Text darin ist für Screenreader unsichtbar — es sei denn, Sie schreiben ihn in den Alt-Text.
Formulare sind für Screenreader-Nutzer die kritischste Interaktion. NVDA wechselt automatisch in den „Fokus-Modus", wenn ein Formularfeld erreicht wird. In diesem Modus werden nur Formularelemente und ihre Labels vorgelesen — kein umgebender Text.
Das bedeutet: Hilfetext, der visuell neben dem Feld steht, wird nicht vorgelesen, wenn er nicht programmatisch verknüpft ist.
<!-- Schlecht: Hinweis wird im Fokus-Modus nicht vorgelesen -->
<label for="phone">Telefonnummer</label>
<span class="hint">Format: +49 123 4567890</span>
<input type="tel" id="phone">
<!-- Gut: Hinweis ist verknüpft -->
<label for="phone">Telefonnummer</label>
<span id="phone-hint" class="hint">Format: +49 123 4567890</span>
<input type="tel" id="phone"
aria-describedby="phone-hint"
autocomplete="tel">
Durch aria-describedby="phone-hint" liest der Screenreader beim Fokussieren des Feldes: „Telefonnummer, Eingabefeld, Format: +49 123 4567890".
Eine der am häufigsten vergessenen Anforderungen. Wenn sich Inhalte auf der Seite dynamisch ändern — ein Artikel wird zum Warenkorb hinzugefügt, eine Fehlermeldung erscheint, eine Suche liefert Ergebnisse — muss der Screenreader darüber informiert werden.
<!-- Höfliche Ankündigung (wartet, bis Screenreader fertig ist) -->
<div aria-live="polite" id="search-results-status"></div>
<!-- Dringende Ankündigung (unterbricht sofort) -->
<div aria-live="assertive" role="alert" id="error-message"></div>
<script>
// Suchergebnisse aktualisieren
function updateSearchResults(count) {
document.getElementById('search-results-status')
.textContent = `${count} Ergebnisse gefunden`;
}
// Fehlermeldung anzeigen
function showError(message) {
document.getElementById('error-message')
.textContent = message;
}
</script>
Die Unterscheidung zwischen polite und assertive ist praxisrelevant. polite für Updates, die der Nutzer wissen sollte, aber die nicht zeitkritisch sind (Suchergebnisse, Warenkorb-Updates). assertive für Dinge, die sofort kommuniziert werden müssen (Fehlermeldungen, Warnungen).
Modale Dialoge sind berüchtigt für Accessibility-Probleme. Die Anforderungen:
aria-hidden="true" oder inert<!-- Natives HTML-Dialog (modern, empfohlen) -->
<dialog id="my-modal" aria-labelledby="modal-title">
<h2 id="modal-title">Produkt hinzugefügt</h2>
<p>Nike Air Max 90 wurde zum Warenkorb hinzugefügt.</p>
<button onclick="this.closest('dialog').close()">
Schließen
</button>
<a href="/warenkorb">Zum Warenkorb</a>
</dialog>
<script>
const dialog = document.getElementById('my-modal');
const trigger = document.getElementById('add-to-cart');
trigger.addEventListener('click', () => {
dialog.showModal(); // Fokus und Trap automatisch!
});
dialog.addEventListener('close', () => {
trigger.focus(); // Fokus zurücksetzen
});
</script>
Das HTML <dialog>-Element mit showModal() kümmert sich automatisch um Focus Trapping und den Escape-Handler. Das ist seit 2023 in allen modernen Browsern unterstützt und spart enorm viel Custom-JavaScript.
Was ich bei jedem Projekt mache — und was ich Ihnen empfehle, zumindest für die kritischen User-Flows:
Die wichtigsten NVDA-Tastenkürzel, die Sie brauchen: