JavaScript Accessibility
Was das Skript ändert, muss es ansagen
Symbolschalter, Aufklappbereich, ausgeblendeter Container: drei Stellen im Skript.
Ausführungsspur
Ein Ereignis muss in drei Welten ankommen
JavaScript ändert nicht nur Pixel. Verfolgen Sie denselben Aufklappvorgang durch Anzeige, Accessibility Tree und Fokusweg. Erst wenn alle drei Spuren zusammenpassen, ist der Zustand verständlich und bedienbar.
- 01Enter am SchalterIm BildSchichtnotizÜbergabe an Team BlauSchichtplan öffnenIm Accessibility Tree
hidden = falsearia-expanded = "true"sichtbar · erweitertIm Fokusweg1SchalterFokus bleibt hier - 02Tab nach dem ÖffnenIm BildSchichtnotizÜbergabe an Team BlauSchichtplan öffnenIm Accessibility Tree
aria-expanded = "true"Link ist erreichbarZustand bleibt stabilIm Fokusweg12Link im Bereich - 03Escape im BereichIm BildSchichtnotizBereich verborgenKein Link im Tab-WegIm Accessibility Tree
hidden = truearia-expanded = "false"verborgen · reduziertIm Fokusweg1zurück zum Schalter
Der typische Bruch
Nur die Pixel werden geschlossen
aria-hidden entfernt Inhalte aus dem Accessibility Tree, aber blendet sie nicht aus. Auf einem Vorfahren mit fokussierbaren Kindern erzeugt es deshalb genau diesen Widerspruch.
Der zweite Ausgabekanal
Status statt Fokuswechsel
Eine kurze Erfolgsmeldung ändert den Kontext nicht. Der Fokus bleibt bei der Aktion; eine bereits vorhandene Statusregion macht den neuen Text wahrnehmbar.
Zum Kopieren
Eine Zustandsfunktion, ein stabiler Fokusweg
Der native Button liefert Enter und Leertaste bereits mit. Das Skript hält nur Sichtbarkeit, ARIA-Zustand, Fokus und Status synchron.
HTML
<button type="button" id="toggle"
aria-controls="notiz" aria-expanded="false">
Schichtnotiz <span aria-hidden="true">⌄</span>
</button>
<div id="notiz" hidden>
<a href="/schichtplan">Schichtplan öffnen</a>
<button type="button" id="save">Notiz speichern</button>
</div>
<p id="status" role="status" aria-atomic="true"></p>JavaScript
const toggle = document.querySelector('#toggle');
const panel = document.querySelector('#notiz');
const save = document.querySelector('#save');
const status = document.querySelector('#status');
function setOpen(open) {
// Vor dem Verbergen merken: Stand der Fokus im Bereich?
const focusWasInside = panel.contains(document.activeElement);
// Ein Wert steuert Bild, Tab-Weg und Accessibility Tree.
panel.hidden = !open;
toggle.setAttribute('aria-expanded', String(open));
// Nur beim Schließen aus dem Bereich zurückführen.
if (!open && focusWasInside) toggle.focus();
}
toggle.addEventListener('click', () => {
// Native Buttons übersetzen Enter und Leertaste in click.
setOpen(panel.hidden);
});
panel.addEventListener('keydown', (event) => {
if (event.key === 'Escape') setOpen(false);
});
save.addEventListener('click', () => {
// Die Region existiert schon; nur ihr Text ändert sich.
status.textContent = 'Schichtnotiz gespeichert.';
});Prüfen Sie die Übergänge, nicht nur den Endzustand
- Öffnen: Enter und Leertaste zeigen den Bereich;
aria-expandedwirdtrue. - Weitergehen: Der erste Tab nach dem Öffnen erreicht den Link im Bereich.
- Schließen: Escape im Bereich verbirgt ihn, setzt den Zustand auf
falseund führt den Fokus zurück. - Überspringen: Im geschlossenen Zustand tauchen Link und Speichern-Schalter nicht im Tab-Weg auf.
- Bestätigen: Nach dem Speichern bleibt der Fokus stehen; ein Vorleseprogramm gibt die Erfolgsmeldung aus.
Aus dem Prüfbericht
Drei Befunde am eigenen Skript
Kritisch aria-expanded meldet einen Wert, den es nicht gibt Regel aria-valid-attr-value
Nur true und false beschreiben den Aufklappzustand. Das Skript setzt den Wert aus derselben Variablen wie die Sichtbarkeit.
Kritisch Der Schalter zeigt nur ein Symbol Regel button-name
Trägt das Icon aria-hidden, bleibt der Button namenlos. Ein aria-label nennt die Aktion, die das Skript auslöst.
Zum Mitnehmen
Die Aufklappfunktion, korrigiert
Ein Zustand, eine Quelle: Sichtbarkeit und ARIA aus derselben Variablen.
Korrektur in 3 Schritten ansehen
Namen und Ausgangszustand am Schalter
Das aria-label nennt die Aktion, die das Skript auslöst. false beschreibt den geschlossenen Bereich, ein erfundener Wert beschreibt nichts.
KorrekturvergleichSchritt 1 · HTML Vorher
<button id="toggle" type="button" aria-controls="notiz" aria-expanded="maybe"> <span aria-hidden="true">▾</span> </button>Nachher
<button id="toggle" type="button" aria-controls="notiz" aria-expanded="false" aria-label="Schichtnotiz öffnen"> <span aria-hidden="true">▾</span> </button>Markierte Zeilen wurden geändert
So prüfen Sie es Gehen Sie mit Tab auf den Schalter. Ein Vorleseprogramm sagt „Schichtnotiz öffnen, reduziert“.
Geschlossenes wirklich schließen
hidden nimmt den Bereich aus Bild und Tab-Weg. Ein aria-hidden lässt den Link darin sichtbar und anspringbar.
KorrekturvergleichSchritt 2 · HTML Vorher
<div id="notiz" aria-hidden="true"> <a href="/schichtplan">Schichtplan öffnen</a> </div>Nachher
<div id="notiz" hidden> <a href="/schichtplan">Schichtplan öffnen</a> </div>Markierte Zeilen wurden geändert
So prüfen Sie es Drücken Sie bei geschlossener Notiz mehrmals Tab. Der Fokus springt nicht mehr ins Verborgene.
Den Zustand aus einer Variablen setzen
Das Skript schreibt Sichtbarkeit und aria-expanded aus demselben Wert. So können Anzeige und Ansage nicht auseinanderlaufen.
KorrekturvergleichSchritt 3 · JavaScript Vorher
toggle.addEventListener('click', () => { notiz.hidden = !notiz.hidden; });Nachher
toggle.addEventListener('click', () => { const offen = notiz.hidden; notiz.hidden = !offen; toggle.setAttribute('aria-expanded', String(offen)); });Markierte Zeilen wurden geändert
So prüfen Sie es Klappen Sie zweimal auf und zu. Die Ansage wechselt zwischen „erweitert“ und „reduziert“.
