Hamburger Menu HTML
Drei Striche brauchen einen Namen
Menübutton, Menülinks, Zustand: drei Stellen im mobilen Menü.
Zustandsplan statt Icon-Trick
Ein Menü, vier Ansichten
Der Breakpoint ändert das Layout. Der Button ändert den Zustand. Beides muss dieselbe Navigation steuern, ohne Links zu duplizieren.
Die vollständige Zustandsmatrix
Bei 48rem wechselt nur die Darstellung. Auf Mobilgeräten entscheidet aria-expanded.
- Button
- sichtbar
- aria-expanded
- false
- nav
- hidden
- Button
- sichtbar
- aria-expanded
- true
- nav
- sichtbar
- Button
- ausgeblendet
- mobiler Zustand
- zurückgesetzt
- nav
- sichtbar
- Button
- ausgeblendet
- mobiler Zustand
- zurückgesetzt
- nav
- sichtbar
A · Beziehung
Drei Werte, eine Entscheidung
Der Schalter trägt den Namen und den Zustand. aria-controls verweist auf die ID der Navigation. hidden bestimmt, ob deren Links gerendert und fokussierbar sind.
aria-controls="hauptmenue"B · Tastaturroute
Öffnen, durchlaufen, sicher zurückkehren
Normale Links bleiben normale Tab-Ziele. Zusätzliche Pfeiltasten und role="menu" sind für eine Seitennavigation nicht nötig.
- TabMenübuttonsichtbarer Fokus
- EnterNavigation offenoder Leertaste
- TabErster Linkdanach Link für Link
- EscMenübuttonschließen + Fokus zurück
C · Referenzimplementierung
Eine Navigation, vollständig verdrahtet
Die Funktion setState schreibt Sichtbarkeit und Ansage gemeinsam. Beim Wechsel auf Desktop wird das Menü sichtbar; beim Rückweg auf Mobil startet es geschlossen.
<button class="nav__toggle" type="button"
aria-expanded="false"
aria-controls="hauptmenue">
<span class="nav__icon" aria-hidden="true"></span>
<span>Menü</span>
</button>
<nav id="hauptmenue"
aria-label="Hauptnavigation" hidden>
<ul class="nav__list">
<li><a href="/leistungen">Leistungen</a></li>
<li><a href="/referenzen">Referenzen</a></li>
<li><a href="/kontakt">Kontakt</a></li>
</ul>
</nav>const toggle = document.querySelector('.nav__toggle');
const nav = document.querySelector('#hauptmenue');
const desktop = matchMedia('(min-width: 48rem)');
function setState(open) {
if (desktop.matches) {
nav.hidden = false;
toggle.setAttribute('aria-expanded', 'false');
return;
}
nav.hidden = !open;
toggle.setAttribute('aria-expanded', String(open));
}
toggle.addEventListener('click', () => {
const open = toggle.getAttribute('aria-expanded') !== 'true';
setState(open);
});
document.addEventListener('keydown', (event) => {
if (event.key !== 'Escape' || nav.hidden || desktop.matches) return;
setState(false);
toggle.focus();
});
desktop.addEventListener('change', () => setState(false));
setState(false);.nav__toggle {
display: inline-flex;
align-items: center;
gap: .6rem;
min-height: 44px;
}
.nav__list {
display: grid;
gap: .75rem;
margin: 1rem 0 0;
}
@media (min-width: 48rem) {
.nav__toggle { display: none; }
.nav__list {
display: flex;
gap: 1.5rem;
margin: 0;
}
}D · Prüfprotokoll
Der Resize-Test gehört dazu
- 320 px
Mit Tab zum Button, mit Enter öffnen, alle Links durchlaufen.
- Escape
Aus einem Link heraus schließen; Fokus muss wieder auf „Menü“ stehen.
- ≥ 48 rem
Fenster verbreitern: Button verschwindet, Navigation bleibt vollständig sichtbar.
- Zurück
Wieder schmal ziehen: Button erscheint mit
false, Navigation ist geschlossen.
Aus dem Prüfbericht
Drei Regeln, drei Befunde
Kritisch Die drei Striche haben keinen Namen Regel button-name
Das Symbol ist mit aria-hidden ausgeblendet, weiterer Text fehlt. aria-label="Menü" gibt der Schaltfläche im Kopfbereich ihren Namen.
Kritisch Ein Menüpunkt besteht nur aus einem Pfeil Regel link-name
Im aufgeklappten Menü führt ein Pfeil ohne Text weiter. Der Name des Ziels gehört in den Linktext.
Kritisch Der Zustand des Menüs ist ungültig Regel aria-valid-attr-value
aria-expanded="maybe" beschreibt keinen Zustand. Geschlossen ist false, offen ist true; das Skript setzt beides.
Zum Mitnehmen
Das mobile Menü, korrigiert
Zwei Änderungen im HTML, eine im Umschalter.
Korrektur in 3 Schritten ansehen
Menübutton benennen und Zustand setzen
aria-label gibt der Schaltfläche ihren Namen. aria-expanded beginnt mit false, weil das Menü geschlossen startet.
KorrekturvergleichSchritt 1 · HTML Vorher
<button id="menue-schalter" type="button" aria-controls="hauptmenue" aria-expanded="maybe"> <span aria-hidden="true">☰</span> </button>Nachher
<button id="menue-schalter" type="button" aria-label="Menü" aria-controls="hauptmenue" aria-expanded="false"> <span aria-hidden="true">☰</span> </button>Markierte Zeilen wurden geändert
So prüfen Sie es Gehen Sie mit der Tabulatortaste auf die drei Striche. Ein Vorleseprogramm sagt „Menü, Schaltfläche, reduziert“.
Den Pfeil-Link beschriften
Der Linktext nennt sein Ziel. Ein Pfeil allein bleibt in der Linkliste eines Vorleseprogramms ein leerer Eintrag.
KorrekturvergleichSchritt 2 · HTML Vorher
<li><a href="/leistungen"><span aria-hidden="true">›</span></a></li>Nachher
<li><a href="/leistungen">Leistungen</a></li>Markierte Zeilen wurden geändert
So prüfen Sie es Öffnen Sie die Linkliste eines Vorleseprogramms. Jeder Menüpunkt trägt dort seinen Namen.
Den Zustand beim Umschalten mitführen
Sichtbarkeit und aria-expanded kommen aus derselben Entscheidung. So stimmt der angesagte Zustand immer mit dem sichtbaren Menü überein.
KorrekturvergleichSchritt 3 · JavaScript Vorher
schalter.addEventListener('click', () => { menue.classList.toggle('offen'); });Nachher
schalter.addEventListener('click', () => { const offen = menue.hasAttribute('hidden'); menue.toggleAttribute('hidden', !offen); schalter.setAttribute('aria-expanded', String(offen)); });Markierte Zeilen wurden geändert
So prüfen Sie es Öffnen und schließen Sie das Menü. Ein Vorleseprogramm wechselt zwischen „erweitert“ und „reduziert“.
