Auf Mobilgeräten ist der Bildschirm schmal, sodass eine horizontale Menüleiste selten passt. Genau hier zeigt das Hamburger-Menü seinen Wert: eine kleine Schaltfläche aus drei Strichen, die beim Antippen die Navigationslinks einblendet. In diesem Artikel bauen wir Schritt für Schritt eine barrierefreie, flüssige mobile Navigation mit reinem HTML, CSS und JavaScript, ganz ohne Bibliotheken.
Das Gerüst: sinnvolles HTML
Ein gutes Menü beginnt mit semantischem Markup, das auch bei deaktiviertem JavaScript sinnvoll bleibt. Schreibe den Auslöser als echten <button>, nicht als <div>. Füge aria-expanded und aria-controls hinzu, damit Screenreader den Zustand verstehen.
<header class="site-header">
<a href="/" class="logo">aslain</a>
<button id="navToggle" class="nav-toggle"
aria-expanded="false"
aria-controls="primaryNav"
aria-label="Menü öffnen">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
<nav id="primaryNav" class="nav">
<ul>
<li><a href="/#about">Über mich</a></li>
<li><a href="/#projects">Projekte</a></li>
<li><a href="/#contact">Kontakt</a></li>
</ul>
</nav>
</header>
Die drei <span class="bar"> sind die Striche des Symbols. Sie in CSS zu zeichnen ist leichter als eine Bilddatei zu verwenden und erlaubt dir, Farbe und Animation mühelos zu steuern.
Das Symbol mit CSS zeichnen
Wir nutzen eine Media Query, um die Schaltfläche nur auf schmalen Bildschirmen anzuzeigen. Auf breiten Bildschirmen ist das Menü bereits horizontal und die Hamburger-Schaltfläche bleibt verborgen.
.nav-toggle {
display: none; /* auf dem Desktop verborgen */
width: 44px;
height: 44px; /* mindestens 44px Berührungsfläche */
background: none;
border: 0;
cursor: pointer;
}
.nav-toggle .bar {
display: block;
width: 24px;
height: 2px;
margin: 5px auto;
background: currentColor;
transition: transform .25s ease, opacity .25s ease;
}
@media (max-width: 760px) {
.nav-toggle { display: block; }
}
Ziele auf eine Berührungsfläche von mindestens 44×44 Pixeln; das ist eine sichere Größe, die der Finger bequem trifft und die Barrierefreiheitsrichtlinien empfehlen.
Die Öffnen- und Schließen-Schicht
Auf schmalen Bildschirmen verbergen wir das Menüpanel standardmäßig und zeigen es, sobald eine Klasse .is-open hinzugefügt wird. Hier transform und visibility statt display: none zu verwenden, hält den Schiebeübergang flüssig.
@media (max-width: 760px) {
.nav {
position: fixed;
inset: 64px 0 0 0; /* beginnt unter dem Header */
background: #0f0f12;
transform: translateX(100%);
visibility: hidden;
transition: transform .3s ease, visibility .3s;
}
.nav.is-open {
transform: translateX(0);
visibility: visible;
}
.nav ul {
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 2rem;
}
}
Die drei Striche in ein „X“ zu verwandeln, signalisiert klar, dass das Menü offen ist. Wir machen das allein mit CSS: Der obere und untere Balken drehen sich, der mittlere verschwindet.
.nav-toggle.is-active .bar:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.nav-toggle.is-active .bar:nth-child(2) {
opacity: 0;
}
.nav-toggle.is-active .bar:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
JavaScript: Zustand und Barrierefreiheit
Die einzige Aufgabe von JavaScript ist es, Klassen umzuschalten und aria-expanded zu aktualisieren. Den Zustand in aria-expanded als einzige Quelle der Wahrheit zu halten, hält den Code sauber.
const toggle = document.getElementById('navToggle');
const nav = document.getElementById('primaryNav');
function setOpen(open) {
toggle.setAttribute('aria-expanded', String(open));
toggle.classList.toggle('is-active', open);
nav.classList.toggle('is-open', open);
toggle.setAttribute('aria-label', open ? 'Menü schließen' : 'Menü öffnen');
}
toggle.addEventListener('click', () => {
const open = toggle.getAttribute('aria-expanded') === 'true';
setOpen(!open);
});
// Menü schließen, wenn ein Link angetippt wird
nav.addEventListener('click', (e) => {
if (e.target.closest('a')) setOpen(false);
});
// Die Escape-Taste schließt das Menü
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') setOpen(false);
});
Drei kleine, aber wichtige Details, die zu beachten sind:
- Schließen bei Linkklick: Auf einer One-Page-Site ist es lästig, wenn das Menü offen bleibt, nachdem der Nutzer zu einem Abschnitt gesprungen ist.
- Escape-Unterstützung: Tastaturnutzer erwarten, dass die
Esc-Taste das Menü schließt. - aria-label-Aktualisierung: Das Umschalten der Beschriftung zwischen „öffnen“ und „schließen“ gibt dem Screenreader die richtige Information.
Fokusverwaltung und Body-Scroll
Zu verhindern, dass die Seite hinter dem Menü scrollt, solange es offen ist, ist auf Mobilgeräten ein wichtiges Detail. Du kannst dem <body> eine Klasse hinzufügen und overflow: hidden anwenden. Den Fokus beim Öffnen auf den ersten Link zu verschieben, macht den Ablauf auch für Tastatur- und Screenreader-Nutzer natürlich.
function setOpen(open) {
/* ...vorherige Zeilen... */
document.body.classList.toggle('nav-locked', open);
if (open) nav.querySelector('a')?.focus();
else toggle.focus();
}
body.nav-locked { overflow: hidden; }
Den Fokus beim Schließen wieder auf die Hamburger-Schaltfläche zurückzugeben, lässt den Nutzer dort weitermachen, wo er aufgehört hat. Diese kleine Fokusrückgabe ist das Markenzeichen einer barrierefreien Komponente.
Die Vorliebe für reduzierte Bewegung respektieren
Manche Nutzer wählen in ihren Systemeinstellungen, Bewegung zu reduzieren. Animationen auszuschalten, um diese Vorliebe zu wahren, ist sowohl höflich als auch barrierefrei.
@media (prefers-reduced-motion: reduce) {
.nav, .nav-toggle .bar { transition: none; }
}
Diese wenigen Zeilen lassen bewegungsempfindliche Nutzer das Menü ohne abrupte Übergänge bedienen, ohne Funktionsverlust.
Häufige Fragen
Warum einen <button> statt eines <div> verwenden?
Ein echter <button> ist per Tastatur fokussierbar, funktioniert mit den Tasten Enter und Leertaste und wird Screenreadern als „Schaltfläche“ angekündigt. Mit einem <div> musst du all das von Hand nachbilden, was zusätzlichen Code und eine Fehlerquelle bedeutet.
Ist ein Bild oder CSS besser für das Hamburger-Symbol?
In den meisten Fällen ist es besser, drei <span>-Elemente mit CSS zu zeichnen: keine zusätzliche Anfrage, die Farbe folgt dem Theme über currentColor, und du kannst die Verwandlung in ein X direkt animieren. SVG ist ebenfalls eine gültige Wahl.
Bei welcher Breite sollte das Menü einklappen?
Es gibt keine feste Regel; schau auf deinen Inhalt. Den Breakpoint dort zu setzen, wo das horizontale Menü nicht mehr passt (oft um 700–800px), funktioniert gut. Teste dein Design, indem du den Browser verschmälerst.
Soll dein mobiles Menü zugleich elegant und barrierefrei sein? Lass uns gemeinsam die Navigation deiner Website durchgehen. Nimm Kontakt auf und lass uns über dein Projekt sprechen.