Enhancing a simple site navigation into an interactive drop-down navigation
Was ist eine Drop-Down-Navigation?
Der Unterschied zwischen einer flachen Navigation und einer Drop-Down-Navigation ist, dass eine Drop-Down-Navigation Elemente enthält, die bei Aktivierung die Anzeige weiterer Elemente toggeln. Sprich: die Funktionalität ist es, verschachtelte Elemente zu verbergen bzw. anzuzeigen, wenn das Elternelement aktiviert wird.
Einige Elemente sind also Disclosure Widgets. Das bedeutet, dass die Elemente, die die Panels toggeln, Buttons sein müssen. Und das schließt gleichzeitig aus, dass das Elternelement selbst ein Link zu einer Unterseite ist. Das schauen wir uns jetzt in Variante 1 an:
Variante 1 - Übergeordneter Navigationspunkt ist kein eigener Link
Der übergeordnete Navigationspunkt ist ein disclosure trigger (ein Button, kein Link), und er öffnet das disclosure panel mit den untergeordneten Navigationspunkten. Wir starten aber mit einer statischen Version der Navigation (damit sie auch funktioniert, wenn kein JavaScript geladen werden kann):
<nav aria-labelledby="nav-label" class="nav--dropdown" id="site-nav">
<span hidden id="nav-label">Site</span>
<ul role="list">
<li data-has-children>
<span>Products</span>
<ul role="list">
<li><a href="/home/" aria-current="page">Kitchen</a></li>
<li><a href="/home/">Bathroom</a></li>
<li data-has-children>
<span>Personal Care</span>
<ul role="list">
<li><a href="#">Hair care</a></li>
<li><a href="#">Face care</a></li>
</ul>
</li>
</ul>
</li>
<li data-has-children>
<span>Team</span>
<ul role="list">
<li><a href="/home/">Get to know us</a></li>
<li><a href="/home/">Contact us</a></li>
</ul>
</li>
<li><a href="#">Press</a></li>
</ul>
</nav> Das Live-Beispiel ist im a11y-playground-Ordner!
JavaScript macht dann folgendes:
- Es ersetzt die
<span>-Elemente durch die disclosure-widget-<button>-Elemente - folgende Elemente werden hinzugefügt:
-
aria-expanded=["true" | "false"]- Panel ist zuerst geschlossen und wird bei Klick geöffnet, dabei wird der Wert true bzw. false getoggelt -
aria-controls="random_id"eine zufällige ID wird generiert, um den Button programmatisch mit dem zugehörigen Panel zu verbinden. (Bei einem einfachen disclosure widget würde die ID einfach panel heißen) - ein
svg, das beim Öffnen und Schließen animiert wird; dieses wird mitaria-hidden="true"vor dem Screenreader versteckt - Die verschachtelten Listen bzw. Panels werden mit dem
hidden-Attribut versteckt* - ... und es fügt der Navigation die Klasse
enhancedhinzu
* Das Verstecken funktioniert aber nicht richtig, weil <ul> ein display: flex; hat und das überschreibt das HTML-Attribut. Link siehe Beispiel im Playground.
[...]
<li data-has-children>
<button aria-expanded="false" aria-controls="random_id">Products
<svg width="1em" height="1em" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" ...></path>
</svg>
</button>
<ul id="random_id" role="list" hidden>
[...]
</ul>
</li>
[...] Die Usability kann mit folgenden Punkten verbessert werden:
- Wenn ein Dropdown ausgeklappt ist, sollte es mit der Esc-Taste geschlossen werden können, um nicht zum disclosure toggle zurücktabben zu müssen, um das Panel zu schließen, zugleich sollte folgendes passieren:
- der Fokus geht zum disclosure toggle zurück, das das Dropdown kontrolliert
- das
aria-expanded-Attribut wird von true auf false upgedatet - in einer verschachtelten Liste geht der Fokus zum zugehörigen Button zurück
- Dropdown schließt, wenn ein Mouse-User woanders hinklickt (inklusive der oberen Punkte)
- Dropdown schließt, wenn der Keyboard-Fokus sich aus der Navigation rausbewegt – das stellt auch sicher, dass SC 2.4.14 Focus not obscured nicht verletzt wird
Arrow-Key Support?
Macht Sinn bei sehr großen Navigationen wie Mega-Drop-Downs. Insbesondere Keyboard-User, die keinen Screenreader benutzen, profitieren davon, da die Navigation insgesamt weniger Tabstops enthält. Arrow Keys sind optional und nicht für barrierefreie Seiten gefordert, da sie aber ihre Berechtigung haben, gibt es im APG ein Kapitel dazu (Example Disclosure Navigation Menu with Top-Level Links)
Variante 2 - übergeordneter Navigationspunkt ist ein Link zu einer Unterseite
Dazu brauchen wir einen Link und einen Button. Wir müssen also einen Button mit dem Link assoziieren. Das disclosure widget wird zu einem Icon Button, der dafür sorgt, dass die verschachtelte Liste auf- und zugeklappt wird, und der Link selbst führt zur Unterseite.
<li>
<!-- The link -->
<a href="/products/" id="products">Products</a>
<!-- + The disclosure widget -->
<button aria-labelledby="products" aria-expanded="true" aria-controls="products-list">
<svg width="1em" height="1em" viewBox="0 0 24 24" aria-hidden="true">...</svg>
</button>
<ul role="list" id="products-list">
<li><a href="/kitchen/">Kitchen</a></li>
<li><a href="/bathroom/">Bathroom</a></li>
<li><a href="/personal-care/">Personal Care</a></li>
</ul>
</li> In diesem Fall verwenden wir keine der bereits bekannten Methoden, um dem Icon Button einen accName zu geben. Der Button wird nach seinem Link benannt. Weiters müssen wir beachten, dass die Icon Buttons groß genug sind, dass sie leicht aktiviert werden können SC 2.5.5 Target Size – Level AAA (44 x 44 CSS Pixel).
Open on hover?
Aufpassen auf 1.4.13 Content on Hover or Focus! Ein Öffnen bei hover passiert oft unbeabsichtigt, und je nach Größe des Panels kann das ganz schön lästig sein. Es kann auch sein, dass der User nicht mitbekommt, dass sich ein Panel geöffnet hat oder das Panel könnte eine Tätigkeit behindern, die gerade ausgeführt werden soll. Wenn sich das Dropdown bei hover öffnet, muss der semantische Status dem sichtbaren entsprechen: aria-expanded muss entsprechend aktualisiert werden. Weiters muss es sich mit der Esc-Taste schließen lassen. Weitere Infos im Artikel der Nielsen Norman Group (Link einfügen!) - timing considerations etc.
Details and summary für eine Drop-Down-Navigation verwenden?
Theoretisch (technisch) möglich, wahrscheinlich sollte man das aber nicht tun. Das <summary>-Element wird von den AT nicht überall gleich behandelt (»summary«, »disclosure triangle«, ...), das gibt dem Screenreader-User keinen eindeutigen Hinweis darauf, was passiert, wenn das Element aktiviert wird. Das ist »functionally inaccessible«.
... und wenn man das Markup nicht verändern kann?
Don't do this. Links als disclosure widgets missbrauchen ist keine gute Idee. Für AT ist es ein Link, aber er hat keine Funktion, bzw. macht etwas unerwartetes. Die Semantik widerspricht dem Verhalten.
Hier kann man nur den Link mit ARIA und JavaScript zu einem Button aufrüsten.
Menus and Toolbars
Für Betriebssysteme, Programme, nicht für Website-Navigationen gedacht.
Relevante Success Criteria
- SC 2.1.1 Keyboard (Level A) – Regel 3
- xxx