Navigation
Eine App ist mehr als eine Seite. Nutzer müssen wissen, wo sie sind und wohin sie können. HTML bringt dafür heute erstaunlich viel mit: Vieles, wofür früher Skriptbibliotheken nötig waren, ist eingebaut.
Was du am Ende kannst
Abschnitt betitelt „Was du am Ende kannst“- ein Hauptmenü semantisch bauen und den aktuellen Punkt markieren
- Untermenüs mit
detailsumsetzen - Brotkrumen und Reiter gestalten
- Dialoge mit
dialogbarrierefrei öffnen
Live-Coding zum Mitmachen
⤓ demo-16-navigation.zip herunterladenDer Ordner starter ist der Ausgangsstand, fertig der Stand nach dem Live-Coding.
Enthält: index.html, stil.css
Das Hauptmenü
Abschnitt betitelt „Das Hauptmenü“Immer dasselbe Muster: nav, eine Liste, Links.
.menue { display: flex; flex-wrap: wrap; gap: 0.25rem; margin: 0; padding: 0; list-style: none; background: #312e81; }.menue a { display: block; padding: 0.75rem 1rem; color: #fff; text-decoration: none; }.menue a:hover { background: #4338ca; }.menue a:focus-visible { outline: 3px solid #fbbf24; outline-offset: -3px; }.menue a[aria-current="page"] { box-shadow: inset 0 -3px #fbbf24; font-weight: 600; }<nav aria-label="Hauptmenü"> <ul class="menue"> <li><a href="#" aria-current="page">Start</a></li> <li><a href="#">Projekte</a></li> <li><a href="#">Team</a></li> </ul></nav>aria-labelbenennt den Bereich, nötig, sobald es mehrerenavauf einer Seite gibt.aria-current="page"kennzeichnet den aktuellen Punkt für Screenreader und ist zugleich dein CSS-Haken.display: blockam Link vergrößert die Klickfläche auf den ganzen Eintrag.
Untermenüs
Abschnitt betitelt „Untermenüs“details und summary sind ein eingebautes Auf- und Zuklappen: mit Tastatur, ansagbar, ohne eine Zeile
JavaScript.
.menue { display: flex; gap: 0.5rem; margin: 0; padding: 0.5rem; list-style: none; background: #e4e7f1; }.menue > li { position: relative; }.menue a, summary { display: block; padding: 0.5rem 0.75rem; color: inherit; cursor: pointer; }details ul { position: absolute; z-index: 1; min-width: 10rem; margin: 0; padding: 0.25rem; list-style: none; background: #fff; box-shadow: 0 4px 12px rgb(0 0 0 / 0.25); }<nav aria-label="Hauptmenü"> <ul class="menue"> <li><a href="#">Start</a></li> <li> <details> <summary>Projekte</summary> <ul> <li><a href="#">Umzug</a></li> <li><a href="#">Sommerfest</a></li> </ul> </details> </li> </ul></nav>Für Menüs, die ein Klick außerhalb schließen soll, reicht details allein nicht. Dafür gibt es Popover (Ausblick
unten) oder ein paar Zeilen JavaScript.
Brotkrumen
Abschnitt betitelt „Brotkrumen“Sie zeigen den Pfad durch eine Hierarchie. Eine geordnete Liste passt genau, die Trenner kommen aus dem CSS.
.krumen { display: flex; flex-wrap: wrap; margin: 0; padding: 0; list-style: none; }.krumen li + li::before { content: "/"; margin-inline: 0.5rem; color: #55606e; }.krumen a[aria-current="page"] { color: inherit; text-decoration: none; }<nav aria-label="Brotkrumen"> <ol class="krumen"> <li><a href="#">Start</a></li> <li><a href="#">Projekte</a></li> <li><a href="#" aria-current="page">Umzug</a></li> </ol></nav>Wenn jeder Reiter eine eigene Seite oder Ansicht ist, baue ihn als gewöhnliches Menü aus Links, das nur wie Reiter aussieht. So funktionieren Lesezeichen und der Zurück-Knopf. Das Muster steht unten im Live-Coding.
Echte Reiter, die auf derselben Seite Bereiche umschalten, brauchen JavaScript und ARIA-Rollen (role="tablist").
Das lohnt sich selten.
Dialoge
Abschnitt betitelt „Dialoge“dialog mit showModal() erledigt alles, was früher schwierig war: Der Dialog liegt über allem, der Rest ist
gesperrt, der Fokus bleibt gefangen, und die Escape-Taste schließt.
dialog { border: 0; border-radius: 0.5rem; box-shadow: 0 8px 32px rgb(0 0 0 / 0.3); }dialog::backdrop { background: rgb(0 0 0 / 0.5); }<button type="button" onclick="document.getElementById('frage').showModal()">Dialog öffnen</button><dialog id="frage" aria-labelledby="frage-titel"> <h2 id="frage-titel">Wirklich löschen?</h2> <form method="dialog"> <button value="nein">Abbrechen</button> <button value="ja">Löschen</button> </form></dialog><form method="dialog">schließt den Dialog beim Absenden, ohne Server.::backdropgestaltet die Abdunklung.- Zum Öffnen brauchst du eine Zeile JavaScript. Mehr dazu im Kapitel Ein wenig JavaScript.
Ausblick: Popover
Abschnitt betitelt „Ausblick: Popover“[popover] { padding: 1rem; border: 1px solid #999; border-radius: 0.5rem; }<button type="button" popovertarget="info">Hinweis ein/aus</button><div id="info" popover>Ein Klick außerhalb oder die Escape-Taste schließt mich.</div>Live-Coding: Das Aufgabenbrett wird navigierbar
Abschnitt betitelt „Live-Coding: Das Aufgabenbrett wird navigierbar“Das Brett bekommt Untermenü, Brotkrumen, Reiter und einen Dialog für neue Aufgaben.
/* Untermenü mit details: aufklappen ohne JavaScript */summary { padding: var(--abstand-s) var(--abstand-m); border-radius: var(--radius); cursor: pointer;}
summary:hover { background: var(--farbe-flaeche);}
summary:focus-visible { outline: 3px solid var(--farbe-fokus);}
details ul { margin-inline-start: var(--abstand-m);}
/* Brotkrumen: Trenner kommen aus dem CSS, nicht in den vorgelesenen Text */.krumen { display: flex; flex-wrap: wrap; margin: 0 0 var(--abstand-s); padding: 0; list-style: none; font-size: 0.875rem;}
.krumen li + li::before { content: "/"; margin-inline: var(--abstand-s); color: var(--farbe-text-leise);}
.krumen a { color: var(--farbe-akzent);}
.krumen a[aria-current="page"] { color: inherit; text-decoration: none;}
/* Reiter: Links, die wie Tabs aussehen */.reiter { display: flex; gap: var(--abstand-s); margin-bottom: var(--abstand-m); border-bottom: 1px solid var(--farbe-linie);}
.reiter a { display: block; padding: var(--abstand-s) var(--abstand-m); border-bottom: 3px solid transparent; color: inherit; text-decoration: none;}
.reiter a:hover { border-bottom-color: var(--farbe-linie);}
.reiter a[aria-current="page"] { border-bottom-color: var(--farbe-akzent); font-weight: 600;}
/* Knöpfe */.knopf { padding: var(--abstand-s) var(--abstand-m); border: 0; border-radius: var(--radius); background: var(--farbe-akzent); color: #fff; font: inherit; cursor: pointer;}
.knopf.leise { background: #e4e7f1; color: var(--farbe-text);}
.filter { display: flex; flex-wrap: wrap; align-items: center; gap: var(--abstand-s);}
.filter .knopf { margin-inline-start: auto;}
/* Dialog: Zentrieren und Abdunkeln erledigt der Browser, wir gestalten nur */dialog { width: min(28rem, 90vw); border: 0; border-radius: var(--radius); box-shadow: var(--schatten);}
dialog::backdrop { background: rgb(0 0 0 / 0.5);}
dialog input { display: block; width: 100%; padding: var(--abstand-s); font: inherit;}
.dialog-knoepfe { display: flex; justify-content: flex-end; gap: var(--abstand-s); margin-top: var(--abstand-m);}Starter für die Übung
⤓ uebung-16-navigation.zip herunterladenZIP-Datei entpacken und den Ordner in VS Code öffnen (Datei → Ordner öffnen).
Enthält: hilfe.html, index.html, stil.css, uebung.css
Die neue Seite hilfe.html hat die Struktur schon. Gestalte sie in uebung.css.
Stufe 1: Brotkrumen
Abschnitt betitelt „Stufe 1: Brotkrumen“.pfad wird eine Zeile, zwischen den Einträgen steht ein ›.
Stufe 2: Reiter
Abschnitt betitelt „Stufe 2: Reiter“.themen zeigt die Themen als Pillen nebeneinander. Das aktuelle Thema fällt auf.
Stufe 3: Fragen
Abschnitt betitelt „Stufe 3: Fragen“Gestalte die details in .fragen als Karten. Eine geöffnete Frage hat eine fette Überschrift (Tipp: details[open]).
Für Schnelle
Abschnitt betitelt „Für Schnelle“Der Dialog „Konto löschen“ warnt deutlich: rote Abdunklung, roter Knopf, und die Knöpfe stehen rechts. Probiere die Tastatur aus: Wo steht der Fokus nach dem Öffnen, und wo nach dem Schließen?