GESIS Leibniz-Institut für Sozialwissenschaften: Homepage aufrufen

Widget Megamenü

Live-Beispiel

HTML-Quelltext

<button id="gs_mm_toggle_button-104618" class="gs_mm_toggle_button" aria-haspopup="true" aria-controls="gs_megamenu-104618" aria-label="Seiten-Navigationsmenü"
></button>
<nav class="gs_megamenu_nav" aria-labelledby="gs_mm_toggle_button-104618">
  <ul role="menu" id="gs_megamenu-104618" class="gs_megamenu">
    <li> <a role="menuitem" href="/styleguide/home">Styleguide Home</a> </li>
    <li class="gs_sub">
      <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/relevante-aspekte">Relevante Aspekte</a> 
      <ul role="menu" >
        <li> <a role="menuitem" href="/styleguide/relevante-aspekte/responsive-design">Responsive Design</a> </li>
        <li class="gs_sub">
          <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/relevante-aspekte/barrierefreiheit">Barrierefreiheit</a> 
          <ul role="menu" >
            <li> <a role="menuitem" href="/styleguide/relevante-aspekte/barrierefreiheit/nvda">NVDA</a> </li>
          </ul>
        </li>
      </ul>
    </li>
    <li> <a role="menuitem" href="/styleguide/gesis-web-frontend-framework">GESIS-Web-Frontend-Framework</a> </li>
    <li class="gs_sub">
      <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/layout">Layout</a> 
      <ul role="menu" >
        <li class="gs_sub">
          <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/layout/html-seitenaufbau">HTML-Seitenaufbau</a> 
          <ul role="menu" >
            <li> <a role="menuitem" href="/styleguide/layout/html-seitenaufbau/partials">Partials</a> </li>
          </ul>
        </li>
        <li> <a role="menuitem" href="/styleguide/layout/grid-layout">Grid-Layout</a> </li>
        <li> <a role="menuitem" href="/styleguide/layout/css-grid-layout">CSS-Grid-Layout</a> </li>
      </ul>
    </li>
    <li class="gs_sub gs_active">
      <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/widgets">Widgets</a> 
      <ul role="menu" >
        <li> <a role="menuitem" href="/styleguide/widgets/akkordeon">Akkordeon</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/box">Box</a> </li>
        <li class="gs_sub">
          <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/widgets/breadcrumbs">Breadcrumbs</a> 
          <ul role="menu" >
            <li> <a role="menuitem" href="/styleguide/widgets/breadcrumbs/unterseite-a">Unterseite A</a> </li>
            <li> <a role="menuitem" href="/styleguide/widgets/breadcrumbs/unterseite-b">Unterseite B</a> </li>
          </ul>
        </li>
        <li> <a role="menuitem" href="/styleguide/widgets/buttons">Buttons</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/dropdown">Dropdown</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/formulare">Formulare</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/karussell">Karussell (Slider)</a> </li>
        <li class="gs_sub">
          <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/widgets/kontakte">Kontakte</a> 
          <ul role="menu" >
            <li> <a role="menuitem" href="/styleguide/widgets/kontakte/kacheln">Kacheln</a> </li>
            <li> <a role="menuitem" href="/styleguide/widgets/kontakte/tabelle">Tabelle</a> </li>
            <li> <a role="menuitem" href="/styleguide/widgets/kontakte/button">Button</a> </li>
          </ul>
        </li>
        <li> <a role="menuitem" href="/styleguide/widgets/mediengalerie">Mediengalerie</a> </li>
        <li class="gs_active"> <a role="menuitem" aria-current="page" href="/styleguide/widgets/megamenue">Megamenü</a> </li>
        <li class="gs_sub">
          <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/widgets/modal">Modal (Dialogfenster)</a> 
          <ul role="menu" >
            <li> <a role="menuitem" href="/styleguide/widgets/modal/modal-via-dialog-element-informativ">Modal via dialog-Element, rein informativ</a> </li>
            <li> <a role="menuitem" href="/styleguide/widgets/modal/modal-via-dialog-element-mit-eingabe">Modal via dialog-Element, mit Eingabe</a> </li>
            <li> <a role="menuitem" href="/styleguide/widgets/modal/deprecated-modal-via-div">DEPRECATED: Modal via div-Element</a> </li>
          </ul>
        </li>
        <li> <a role="menuitem" href="/styleguide/widgets/mouseoverbox">Mouseoverbox</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/paginierung">Paginierung</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/skiplinks">Skiplinks</a> </li>
        <li> <a role="menuitem" href="/styleguide/widgets/tabs">Tabs</a> </li>
      </ul>
    </li>
    <li> <a role="menuitem" href="/styleguide/schriftarten">Schriftarten</a> </li>
    <li class="gs_sub">
      <a role="menuitem" aria-haspopup="true" aria-expanded="false" href="/styleguide/icons">Icons</a> 
      <ul role="menu" >
        <li> <a role="menuitem" href="/styleguide/icons/svg">SVG</a> </li>
      </ul>
    </li>
    <li> <a role="menuitem" href="/styleguide/farben">Farben</a> </li>
  </ul>
</nav>

HTML-Aufbau

  • <button id="gs_mm_toggle_button-104618" class="gs_mm_toggle_button" aria-haspopup="true" aria-controls="gs_megamenu-104618" aria-label="Navigationsmenü" ></button> : kontrollierender Button des Megamenüs. Muss immer vorhanden sein und ist Ausgangspunkt für die (JavaScript-)Initialisierung des Megamenüs. Auch wenn dieser Button in Desktopansichten nicht sichtbar ist, muss dieser Button vorhanden sein, um auch auf kleineren Bildschirmen und auf Geräten ohne Mauseingabe eine Interaktion mit dem Megamenü zu ermöglichen.
    Die Position des Buttons und des Megamenüs (Wurzel-ul-Element) sind voneinander unanbhängig und können sich an verschiedenen Stellen innerhalb des HTML-Dokumentes befinden, sollten aber in visueller und semantischer Nähe liegen. Button und Megamenü werden über das Button-Attribut aria-controls miteinander verknüpft. 
    • Attribut id : notwendig und muss eindeutig sein. Wird für nav-Element (siehe nachfolgend) benötigt, um dieses zu gelabeln (u.a. für Screenreader wichtig).
    • Attribut class="gs_mm_toggle_button" : Marker-Klasse, um Megamenü-Charakter dieses Buttons (und seines aria-controls-Elements) zu an JavaScript und CSS zu kommunizieren.
    • Attribut aria-haspopup="true" : notwendig für Barrierefreiheit
    • Attribut aria-controls="gs_megamenu-104618" : notwendig. ID jenes HTML-ul-Elements, welches die Megamenü-Struktur beinhaltet.
    • Attribut aria-label="Navigationsmenü" : Aussagekräftiger Name der Funktion des von diesem Button gesteuerten Megamenüs
  • <ul role="menu" id="gs_megamenu-104618" class="gs_megamenu"> : Wrapper für Megamenü-Struktur
    • Attribut role="menu" : notwendig, um Menücharakter an Screenreader zu kommunizieren
    • Attribut id="gs_megamenu-104618" : notwendig und muss eindeutig sein. Wird vom kontrollierendem Button mit seinem Attribut aria-controls referenziert.
    • Attribut class="gs_megamenu" : Notwendig für korrektes CSS-Styling.
    • <li (class="gs_sub gs_active")> : für jeden Top-Level-Megamenü-Eintrag gibt es ein li-Element. In Desktop-Ansichten werden diese Elemente als nebeneinander ähnlich der Einträge eines Menubars angezeigt:
      • Attribut class="gs_sub" : Wenn ein li-Element Untereinträge besitzt (also ein ul-Element-Kind hat), muss diese Klasse vorhanden sein. Anmerkung: diese Klasse erfüllt rein stilistischen (CSS-)Zweck zur Darstellung von "Öffnen/Schließen"-Caret-Piktogrammen in der Mobildarstellung und wird wegfallen können, sobald die CSS-Pseudoklasse :has() vom Großteil der Browser unterstützt wird (2022+) (li:has(> ul)).
      • Attribut class="gs_active" : Wenn sich die aktuelle Seite (beliebig tief) innerhalb dieses li-Element befindet, muss diese Klasse vorhanden sein. Anmerkung: diese Klasse erfüllt rein stilistischen (CSS-)Zweck zur farblichen Hervorhebung des aktuellen Seitenpfades und wird wegfallen können sobald die CSS-Pseudoklasse :has() vom Großteil der Browser unterstützt wird (2022+) (li:has(a[aria-page="current"]) > a).
      • <a role="menuitem" href="..." (aria-haspopup="true" aria-expanded="false" aria-current="page")> : Ein Navigationseintrag des Megamenus:
        • Attribut role="menuitem" : verpflichtendes Attribut, um an Screenreader den Charakter Menüeintrag zu kommunizieren
        • Attribut href="..." : verpflichtendes Attribut mit der URL, zu der dieser Menüeintrag navigieren soll.
        • Attribut aria-haspopup="true" : wenn dieser Menüeintrag ein Untermenü hat, muss aria-haspopup="true" gesetzt sein. Wichtig, um das Vorhandensein eines Untermenüs an Screenreader zu kommunizieren.
        • Attribut aria-expanded="false" : wenn dieser Menüeintrag ein Untermenü hat, muss aria-expanded vorhanden sein. Standardmäßig hat dieses Attribut den Wert "false" (Untermenü ist geschlossen). Wichtig, um an Screenreader den aktuellen Zustand des Untermenüs zu kommunizieren (geschlossen oder geöffnet). Die JavaScript-Bibliothek übernimmt die automatische Zustandsaktualisierung dieses Attributs in Abhängigkeit von Benutzerinteraktionen (Tastaturinteraktion, um das Untermenü zu öffnen, sowie bei Hovern über diesem Menüeintrag mit dem Mauszeiger).
        • Attribut aria-current="page" : wenn die aktuelle Seite diesem Menüeintrag entspricht, sollte dieser Menüeintrag diesen Attribut-Wert-Paar haben (dient der Orientierung speziell bei Verwendung von Screenreadern).
      • <ul role="menu"> : Optionales Element bei Vorhandensein von Submenüs.
        Der weitere Aufbau entspricht den zuvor genannten Regeln.
        Aus UX-Gründen soll ein Megamenü nicht mehr als drei verschachtelte ul-Ebenen haben.

Initialisierungscode

import { Menubutton } from './js/gesis-megamenu.js';
import { fadeMainContent, unfadeMainContent } from './js/gesis-helpers.js';

document.addEventListener('DOMContentLoaded', function() {

  const menuButtonsElements = document.getElementsByClassName('gs_mm_toggle_button');
  for (const menuButtonElement of menuButtonsElements) {
    const menuButtonElementId = menuButtonElement.id;
    const menubutton = new Menubutton(
      menuButtonElement,
      function() {fadeMainContent(this.mainController.popupMenu.parentNav, this.mainController.domNode);},
      function() {unfadeMainContent(this.mainController.popupMenu.parentNav, this.mainController.domNode);}
    );
    menubutton.init();
  }

});
  • Jedes Megamenü benötigt einen Menubutton ( <button class="gs_mm_toggle_button" ...></button> ), selbst wenn seine Darstellung auf Desktopbildschirmen mit Mausbedienung versteckt ist. Über diesen Menubutton initialisiert die JavaScript-Bibliothek das gesamte Megamenü (Button plus <nav class="gs_megamenu_nav" ...><ul class="gs_megamenu" ...> ... </ul></nav> ).
  • Der MenuButton-Konstruktor hat zwei optionale Parameter, über welche Callback-Funktionen übergeben werden können, die beim Öffnen respektive Schließen des Megamenü ausgeführt werden. Im vorherigen Initialisierungscode-Beispiel werden zwei Funktionen übergeben, welche unter Zuhilfenahme von fadeMainContent und unfadeMainContent den Rest der Webseite verkunkeln, solange das Megamenü geöffnet ist.

Barrierefreiheit

  • Teilkomponente Menubutton: implementiert W3C-WAI-ARIA-Spezifikation Menu Button. Siehe Navigation Menu Button Example.
  • Teilkomponente Navigationshierarchie: implementiert W3C-WAI-ARIA-Spezifikation Menu als Hybrid aus Navigation Menubar (hierarchisch) und Disclosure Navigation Menu with Top-Level Links (verlinkte Überkategorien).
    • Siehe menu role.
    • Bedienung ist auch ausschließlich per Tastatur möglich:
      • Die JavaScript-Bibliothek kümmert sich automatisch um eine logische Aktualisierung des tabindex der Megamenü-Einträge. Dadurch wird erreicht, dass bei einer Vielzahl von Megamenü-Einträgen der Benutzer weiterhin auf der gesamten Webseite effizient per Tabben navigieren kann, ohne eine "Tab-Durststrecke hunderter Menüeinträge" durchzutabben.
      • Menüeinträge innerhalb einer Hierarchieebene können mit den Pfeiltasten hervorgehoben werden. Leertaste öffnet tiefere Hierarchieebenen, Escape verlässt die aktuelle Hierarchieebene. Eingabetaste navigiert zum hervorgehobenen Eintrag. Durch wiederholtes Drücken von Zeichentasten (Buchstaben, Zahlen) kann ebenfalls direkt Einträge hervorgehoben werden, deren Titel mit dem gedrückten Zeichen beginnen.

Responsive Design

  • Wenn der Bildschirm Desktopgröße hat UND Mausbedienung (Pointer) vorhanden ist, dann wird das Megamenü als horizontales Menubar für die primäre Hierarchieabene und Popups für tiefere Hierarchieebenen dargestellt. In dieser Darstellungsweise ist der Menubutton versteckt. Die Popups erscheinen beim Mauszeiger-Hovern über dem korrespondierenden Übereintrag (oder durch Tastaturbedienung). Ein Mauszeiger-Klick hingegen navigiert zur Seite des Übereintrags.
  • Wenn der Bildschirm Smartphonegröße hat ODER keine Mausbedienung (kein Pointer, z.B. nur Touchbedienung) vorhanden ist, dann wird der Menubutton dargestellt. Durch Klick auf diesen Menubutton zeigt sich das Megamenü in einer hierarchischen Darstellung ähnlich verschachtelter Akkordeons.
  • Trotzdem Tablets große Bildschirme haben, wird das Megamenü wie auf Smartphones als "Menubutton mit verschachtelten Akkordeons" angezeigt. Das hat damit zu tun, dass Tablets im Allgemeinen kein Pointer-Device (Mauszeiger) haben und daher kein Hover-Event für die Darstellung der Untermenü-Popups ausgelöst werden kann. Die Darstellungsweise "Menubutton mit verschachtelten Akkordeons" lässt sich hingegen vollständig per Touch-Device (oder auch Tastatur) bedienen.