Die Mitgliederversammlung findet am 25.11.2023 um 10:00 statt; davor und danach gibt es Gelegenheiten zum gemütlichen Beisammensein.
Weitere Informationen und eine Anmeldemöglichkeit gibt es in der Veranstaltungs-Ankündigung.
Navigation/Dropdown-Menü
Text-Info
- 30min
- einfach
- Grundkenntnisse in
● Navigation/Grundstruktur
● Links/Gestaltung mit CSS
In diesem Kapitel lernen Sie die Funktionsweise einer Dropdown-Navigation kennen, die sich mit Maus und Tastatur auf- und zuklappen lässt.
Dies war früher ein Paradebeispiel für die Power von CSS und dem durch die Maus ausgelösten Hover. Heute haben sich die Anforderungen geändert. Eine solche Navigation muss sich …
- responsiv an alle Viewports anpassen und die Links auf kleinen Bildschirmen untereinander anordnen.
- auch auf Touchgeräten ohne Maus funktionieren
- mit den Pfeil- oder Tabtasten anwählbar sein
Inhaltsverzeichnis
Dropdown nur mit CSS
Navigationen bei größeren Webprojekten enthalten in vielen Fällen keine sequenzielle Auflistung von Links, sondern verteilen diese auf verschiedene Navigationsebenen.
HTML: verschachtelte Listen
Zur logischen Abbildung dieser Struktur eignen sich verschachtelte Listen.
<nav>
<ul>
<li><a href="#">Seite 1</a></li>
<li><a href="#">Seite 2</a>
<ul>
<li><a href="#">Seite 2a</a></li>
<li><a href="#">Seite 2b</a></li>
</ul>
</li>
<li aria-current="page"><a href="#">aktuelle Seite</a></li>
<li><a href="#">Seite 4</a>
<ul>
<li><a href="#">Seite 4a</a></li>
<li><a href="#">Seite 4b</a></li>
<li><a href="#">Seite 4c</a></li>
</ul>
</li>
<li><a href="#">Seite 5</a></li>
<li><a href="#">Seite 6</a></li>
</ul>
</nav>
In das zweite und vierte li
-Element ist hier eine weitere Liste eingefügt, da Listen wie ul
oder ol
selbst keine anderen Elemente als li
als direktes Nachfahrenelement enthalten dürfen.
Selbst ohne CSS wird die Struktur von verschachtelten Listen über die Browser-Voreinstellungen sehr gut deutlich.
Mit der Tastatur können alle Links ausgewählt werden.
nav > ul {
...
}
@media (min-width: 45em) {
nav > ul {
...
}
}
Die Formatierung der ersten Navigationsebene bleibt erhalten. Damit nur die Elemente der ersten Ebene angesprochen werden, werden sie über den Kindselektor nav > ul
selektiert.
Die Listen der zweiten Ebene erhalten eine Klasse submenu
.
Submenü ausblenden
Kennzeichen eines Dropdown-Menüs ist, dass das Submenü im Originalzustand ausgeblendet ist und erst beim Auswählen mit der Maus über die Pseudoklasse :hover
oder mit der Tastatur über :focus
selektiert und sichtbar gemacht wird.
/* submenu navigation links */
nav .submenu {
visibility: hidden;
height: 0;
z-index: 1000;
}
nav .submenu li {
display: block;
width: 15em;
}
/** Show the submenu on hover, focus **/
nav li:hover .submenu,
nav li:active .submenu,
nav li:focus .submenu {
visibility: visible;
height: auto;
}
Die Listen der zweiten Ebene erhalten eine Klasse submenu
, die im Normalzustand mit visibility: hidden
ausgeblendet ist.
Listenelemente, die als Kindelement ein Submenü beinhalten, erhalten einen tabindex="0"
, damit sie antabbar sind.
Wenn Sie mit der Maus oder über die Tastatur ausgewählt werden, wird das Submenü eingeblendet; die folgenden Listenpunkte rutschen nach unten.
Wie kann ein Nutzer aber erkennen, dass ein (jetzt ausgeblendetes) Submenü vorhanden ist?
nav .subtitle::after {
position: absolute;
content: " ▶";
color: currentColor;
display: inline-block;
width: 2em;
right:0;
}
nav .subtitle:hover::after, nav .subtitle:focus::after{
content:" ▼";
}
Menüpunkte, die Untermenüs enthalten werden, erhalten nun after-Pseudoelemente. Diese erhalten über die content-Eigenschaft Rechtspfeile, die absolut am rechten Rand positioniert werden. Diese werden mit currentColor in der aktuellen Textfarbe eingefärbt.
Im Beispiel haben die Menüpunkte die Klasse .subtitle
erhalten, da CSS bisher keine nachfolgenden Elemente selektieren konnte. Diese wäre mit has() mittlerweile möglich.
Achtung!
Sie können die bis jetzt vorgestellten Navigationen mit der Maus ansteuern und bedienen. Mit der Tastatur können Sie nur die dargestellten, aber nicht die ausgeblendeten Verweise ansteuern.
- Man kann zwar die Submenüs über das tabindex des li-Elements sichtbar machen, die Listeneinträge jedoch nicht mit der Tastatur durchtabben.
- Wenn man über den Geschwisterselektor
a:hover ~ .submenu
selektiert, wird das Submenu ein- , sobald der erste Listenpunkt angewählt wird, aber doch wieder ausgeblendet.
Eine touch- und tastaturbedienbare Variante lässt sich nur mit JavaScript erreichen: → inklusives Dropdown-Menü
--Matthias Scharwies (Diskussion) 08:09, 31. Okt. 2017 (CET)Wäre es nicht besser, wenn man die Pfeile anklicken und so das Submenü öffnen könnte?
Viele Anfänger versuchen in ihren Webseiten mit HTML und CSS auszukommen. Dies ist auch völlig korrekt:- HTML zeichnet den Inhalt möglichst semantisch und sparsam aus.
- CSS sorgt für die Gestaltung
- Mit einigen Zeilen JavaScript können wir aber unsere Navigation um Zusatzfunktionen erweitern, damit sie für alle Nutzer wirklich benutzbar ist!
Dabei muss das HTML nicht verändert werden. JavaScript wird in einer zusätzlichen Schicht als progressive enhancement (schrittweise Verbesserung) verwendet.
inklusives Dropdown-Menü
Dieses Beispiel erweitert die CSS-basierte Variante um einige Zusatzfunktionen, die das Dropdown-Menü für alle benutzbar machen.[1]
Ziele sind:
- HTML: verschachtelte Listen mit bis zu drei Ebenen ohne Klassen
- CSS: Auf schmalen Viewports vertikal - auf genügend breiten Viewports horizontal angeordnet.
- JavaScript Bedienung mit Maus, Touch und Tastatur
- die oben vorgestellten Dreiecke werden interaktiv
- ESC schließt das aufgeklappte Menü
Button erzeugen
Grundproblem der CSS-basierten Variante ist die Möglichkeit mit der Maus über einem Listenelement zu hovern (und so das Untermenü sichtbar zu machen) und es anschließend anzuklicken, um den Link auszulösen. Während es auf Touchgeräten schwierig ist, zwischen einem sanften Tab und einem festen Klick zu unterscheiden, ist diese doppelte Interaktion mit der Tastatur unmöglich.
Deshalb fügen wir nun jedem Listenelement, dem auf den Link eine Unterliste (=Untermenü) folgt, einen Button hinzu, der diese Funktionalität ermöglicht.
<nav>
<ul>
<li><a href="#">Seite 2</a>
<button aria-expanded="false">
<span class="visually-hidden">Untermenü aufklappen</span>
</button>
<ul>
<li><a href="#">Seite 2a</a></li>
<li><a href="#">Seite 2b</a></li>
</ul>
</li>
...
Zwischen dem Link und dem Untermenü befindet sich nun ein Button. Durch das aria-expanded-Attribut wird angezeigt, dass er das folgende Element auf- und zuklappen kann. (Die explizite Zuordnung über ein aria-controls
-Attribut ist laut Heydon Pickering bei aufeinanderfolgenden Elementen nicht nötig.[2]).
Obwohl der Button einen Pfeil anzeigen soll, wird hier in einem span ein Hinweistext notiert, der über die Klasse visually-hidden
auf Bildschirmen versteckt wird. Ein aria-label würde zwar von Screenreadern vorgelesen, aber nicht übersetzt.[3]
Das folgende JavaScript erzeugt nun unsere Buttons:
const submenus = document.querySelectorAll('nav li > ul');
for(let submenu of submenus) {
submenu.classList.add('submenu');
submenu.insertAdjacentHTML('beforebegin', `
<button aria-expanded="false">
<span class="visually-hidden">Untermenü aufklappen</span>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'>
<path d='M0.3,0.1 0.3,0.9 0.8,0.5z' />
</svg>
</button>
`);
}
Mit querySelectorAll('nav li > ul') können wir nun alle Submenüs, die direkte Kinder eines li sind, finden. Die gefundenen Ergebnisse sind nun in einer node list, die mit einer for..of-Schleife jetzt für jeden Treffer den oben besprochenen Button mit insertAdjacentHTML einfügt.
Und nun wird der Text des Buttons durch einen SVG-Pfeil ersetzt und das Untermenü ausgeblendet:
.visually-hidden {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px) !important;
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden !important;
}
[aria-expanded] {
position: absolute;
...
background: transparent;
outline:transparent;
border: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath d='M0.3,0.1 0.3,0.9 0.8,0.5z' fill='white'/%3E%3C/svg%3E");
background-repeat: no-repeat;
}
Die Klasse visually-hidden
versteckt den Text visuell[4], für Screenreader ist er aber weiterhin erreichbar, die so eine Anleitung erhalten. Sehende werden durch den als Hintergrundbild angezeigten Pfeil geleitet.
Siehe auch:
Auf- und Zuklappen
document.documentElement.addEventListener('click', event => {
if (event.target.tagName == 'BUTTON' && event.target.hasAttribute('aria-expanded')) {
event.target.setAttribute('aria-expanded', event.target.getAttribute('aria-expanded') != 'true');
event.target.querySelector('path').setAttribute('fill', 'lime');
event.target.nextElementSibling.classList.toggle('visible');
}
});
document.addEventListener('keyup', (e) => {
if (e.key === 'Escape') {
document.querySelector('.visible').classList.remove('visible');
}
});
ToDo (weitere ToDos)
Bitte gebt mir Rückmeldung im Forum, wie ich hier weitermachen soll!
--Matthias Scharwies (Diskussion) 07:04, 20. Feb. 2023 (CET)Bei einer Tastaturbedienung sollte man auch mit den Pfeiltasten navigieren können. Normalerweise würde man mit rechter Pfeiltast zum nächsten li der selben Ebene; mit Pfeiltaste unten in die nächste Unterliste gehen. Bei unserem responsivem Dropdown stehen wir vor dem Problem, dass es ab 45em Breite von column
(senkrecht) auf row
(waagerecht) umschaltet und dann die Pfeilrichtingen geändert werden müssten.
ToDo (weitere ToDos)
Kopiervorlage für Ungeduldige
Quellen
- ↑ Eine Vorgänger-Version von Beatovich aus dem Jahr 2011 finden Sie in unserem Museum: Museum/Eine zugängliche Multilevel-Dropdown-Navigation
- ↑ Aria-Controls is Poop (heydonworks.com)
- ↑ auto-translation of `aria-label` - Do not rely on it! (Adrian Roselli on twitter)
- ↑ https://github.com/h5bp/html5-boilerplate/blob/main/dist/css/style.css