HTML Dropdown-Menüs

Dropdown-Navigation mit CSS (Hover) und JavaScript (Klick) - mit funktionierenden Demos zum Ausprobieren.

Was ist ein Dropdown-Menü?

Ein Dropdown-Menü zeigt Unterpunkte erst an, wenn der Nutzer mit dem Hauptpunkt interagiert. Das spart Platz und hält die Navigation übersichtlich.

Es gibt zwei Varianten:

Hover-Dropdown

  • Öffnet beim Überfahren mit der Maus
  • Nur CSS nötig
  • Schneller Zugriff auf Desktop
  • Problematisch auf Touch-Geräten

Klick-Dropdown

  • Öffnet erst bei Klick/Tap
  • Braucht JavaScript
  • Funktioniert auf allen Geräten
  • Bessere Kontrolle für den Nutzer
Welche Variante wählen?

Empfehlung: Für moderne Websites ist die Klick-Variante meist die bessere Wahl. Sie funktioniert auf Smartphones, Tablets und Desktop gleichermaßen und gibt dem Nutzer mehr Kontrolle.

Hover-Dropdowns sind okay für reine Desktop-Anwendungen oder als zusätzliche Komfort-Funktion (Hover + Klick kombiniert).

Hover-Dropdown (nur CSS)

Die einfachste Variante: Das Dropdown öffnet sich, wenn der Nutzer mit der Maus über den Menüpunkt fährt. Dafür reicht CSS - kein JavaScript nötig.

HTML-Struktur

HTML
<nav aria-label="Hauptnavigation">
    <ul class="menu-demo">
        <li><a href="/">Home</a></li>
        
        <li class="dropdown-demo">
            <a href="/tutorials/">Tutorials</a>
            <ul class="dropdown-menu-demo">
                <li><a href="/tutorials/html/">HTML</a></li>
                <li><a href="/tutorials/css/">CSS</a></li>
                <li><a href="/tutorials/js/">JavaScript</a></li>
            </ul>
        </li>
        
        <li><a href="/kontakt/">Kontakt</a></li>
    </ul>
</nav>

Demo: Fahre mit der Maus über "Tutorials"

CSS anzeigen
CSS
/* Hauptmenü */
.menu-demo {
    display: flex;
    gap: 2rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.menu-demo > li {
    position: relative;              /* Anker für absolutes Dropdown */
}

.menu-demo a {
    color: var(--text-primary);
    text-decoration: none;
    padding: 0.5rem 0;
    display: block;
}

/* Dropdown-Container */
.dropdown-demo {
    position: relative;
}

/* Dropdown-Menü (versteckt) */
.dropdown-menu-demo {
    position: absolute;
    top: 100%;                       /* Direkt unter dem Trigger */
    left: 0;
    min-width: 180px;
    
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
    
    list-style: none;
    padding: 0.5rem 0;
    margin: 0;
    
    /* Animation */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: all 0.3s ease;
    
    z-index: 100;
}

/* HOVER: Dropdown einblenden */
.dropdown-demo:hover .dropdown-menu-demo {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

/* Links im Dropdown */
.dropdown-menu-demo a {
    padding: 0.5rem 1rem;
    display: block;
}

.dropdown-menu-demo a:hover {
    background: var(--bg-secondary);
}
Achtung: Touch-Geräte!

Hover funktioniert nicht auf Smartphones und Tablets! Der erste Tap öffnet das Dropdown, der zweite folgt dem Link - das ist verwirrend für Nutzer.

Lösung: Verwende die Klick-Variante oder kombiniere beide Ansätze.

Klick-Dropdown (mit JavaScript)

Die robustere Variante: Das Dropdown öffnet sich erst bei Klick oder Tap. Das funktioniert auf allen Geräten und gibt dem Nutzer mehr Kontrolle.

HTML-Struktur

HTML
<nav aria-label="Hauptnavigation">
    <ul class="menu-click">
        <li><a href="/">Home</a></li>
        
        <li class="dropdown-click">
            <a href="#" 
               aria-expanded="false" 
               aria-haspopup="true">Tutorials</a>
            <ul class="dropdown-menu-click">
                <li><a href="/tutorials/html/">HTML</a></li>
                <li><a href="/tutorials/css/">CSS</a></li>
                <li><a href="/tutorials/js/">JavaScript</a></li>
            </ul>
        </li>
        
        <li><a href="/kontakt/">Kontakt</a></li>
    </ul>
</nav>

Demo: Klicke auf "Tutorials"

CSS anzeigen
CSS
/* Hauptmenü (identisch zur Hover-Variante) */
.menu-click {
    display: flex;
    gap: 2rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.menu-click > li {
    position: relative;
}

/* Dropdown-Trigger */
.dropdown-click > a {
    cursor: pointer;
    user-select: none;           /* Verhindert Textauswahl */
}

/* Pfeil-Indikator */
.dropdown-click > a::after {
    content: ' ▼';
    font-size: 0.7em;
    margin-left: 0.3rem;
    display: inline-block;
    transition: transform 0.3s;
}

/* Pfeil dreht sich wenn offen */
.dropdown-click.open > a::after {
    transform: rotate(180deg);
}

/* Dropdown-Menü (versteckt) */
.dropdown-menu-click {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 180px;
    
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
    
    list-style: none;
    padding: 0.5rem 0;
    margin: 0;
    
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: all 0.3s ease;
    
    z-index: 100;
}

/* OFFEN: via JavaScript-Klasse */
.dropdown-click.open > .dropdown-menu-click {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
JavaScript anzeigen
JavaScript
document.addEventListener('DOMContentLoaded', function () {

    // Alle Dropdown-Trigger finden
    const dropdownTriggers = document.querySelectorAll('.dropdown-click > a');

    // Hilfsfunktion: Dropdown öffnen/schließen
    function toggleDropdown(trigger) {
        const dropdown = trigger.parentElement;
        const isOpen = dropdown.classList.contains('open');

        // Alle anderen Dropdowns schließen
        document.querySelectorAll('.dropdown-click.open').forEach(open => {
            if (open !== dropdown) {
                open.classList.remove('open');
                const openTrigger = open.querySelector('a[aria-expanded]');
                if (openTrigger) openTrigger.setAttribute('aria-expanded', 'false');
            }
        });

        // Dieses Dropdown togglen
        dropdown.classList.toggle('open');
        trigger.setAttribute('aria-expanded', !isOpen);
    }

    // Hilfsfunktion: Alle Dropdowns schließen
    function closeAllDropdowns() {
        document.querySelectorAll('.dropdown-click.open').forEach(open => {
            open.classList.remove('open');
            const trigger = open.querySelector('a[aria-expanded]');
            if (trigger) trigger.setAttribute('aria-expanded', 'false');
        });
    }

    dropdownTriggers.forEach(trigger => {
        // Klick-Event
        trigger.addEventListener('click', function (e) {
            e.preventDefault();
            toggleDropdown(this);
        });

        // Keyboard-Event (Enter und Space)
        trigger.addEventListener('keydown', function (e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                toggleDropdown(this);
            }
        });
    });

    // Klick außerhalb schließt alle Dropdowns
    document.addEventListener('click', function (e) {
        if (!e.target.closest('.dropdown-click')) {
            closeAllDropdowns();
        }
    });

    // ESC-Taste schließt Dropdowns
    document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape') {
            closeAllDropdowns();
        }
    });
});

Bei Touch-Geräten oder wenn der User mehr Kontrolle haben soll, ist es oft besser, Dropdowns erst bei Klick zu öffnen statt bei Hover. Das braucht ein bisschen JavaScript.

HTML
<nav>
    <ul class="menu-click">
        <li><a href="#">Home</a></li>
        <li class="dropdown-click">
            <a href="#">Themen</a>
            <ul class="dropdown-menu-click">
                <li><a href="#">HTML</a></li>
                <li><a href="#">CSS</a></li>
                <li><a href="#">JavaScript</a></li>
            </ul>
        </li>
    </ul>
</nav>
Details zum CSS
CSS
/* Hauptmenü */
.menu-click {
    display: flex;
    gap: 2rem;
    list-style: none;
    align-items: center;
    margin: 0;
    padding: 0;
}

.menu-click > li {
    position: relative;
}

/* Toggle-Element */
.dropdown-click {
    position: relative;
}

.dropdown-click > a {
    cursor: pointer;                    /* Zeigt Klickbarkeit */
    user-select: none;                  /* Verhindert Textauswahl */
}

/* Pfeil-Indikator */
.dropdown-click > a::after {
    content: ' ▼';
    font-size: 0.7em;
    transition: transform 0.3s;
    display: inline-block;
}

/* Pfeil dreht sich wenn offen */
.dropdown-click.open > a::after {
    transform: rotate(180deg);
}

/* Dropdown-Menü (versteckt) */
.dropdown-menu-click {
    position: absolute;
    top: 100%;
    left: 0;
    background: var(--dark-light);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    min-width: 180px;
    list-style: none;
    padding: 0.5rem 0;
    margin: 0;
    
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: all 0.3s ease;
    
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
    z-index: 100;
}

/* KLICK: Sichtbar via .open Klasse */
.dropdown-click.open > .dropdown-menu-click {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
Details zum JavaScript
JavaScript
// Alle Dropdown-Trigger finden
document.querySelectorAll('.dropdown-click > a').forEach(trigger => {
    trigger.addEventListener('click', function(e) {
        e.preventDefault();                     // Link-Verhalten verhindern
        
        const dropdown = this.parentElement;    // Das li.dropdown-click
        
        // Alle anderen Dropdowns schließen
        document.querySelectorAll('.dropdown-click.open').forEach(open => {
            if (open !== dropdown) {
                open.classList.remove('open');
            }
        });
        
        // Dieses Dropdown togglen
        dropdown.classList.toggle('open');
    });
});

// Klick außerhalb schließt alle Dropdowns
document.addEventListener('click', function(e) {
    if (!e.target.closest('.dropdown-click')) {
        document.querySelectorAll('.dropdown-click.open').forEach(open => {
            open.classList.remove('open');
        });
    }
});

Accessibility (Barrierefreiheit)

Damit Dropdowns für alle Nutzer zugänglich sind - auch für Menschen, die Screenreader oder nur die Tastatur verwenden:

ARIA-Attribute

HTML
<li class="dropdown-click">
    <a href="#" 
       aria-expanded="false"
       aria-haspopup="true">
        Tutorials
    </a>
    <ul class="dropdown-menu-click" role="menu">
        <li role="menuitem"><a href="#">HTML</a></li>
        <li role="menuitem"><a href="#">CSS</a></li>
    </ul>
</li>
  • aria-expanded - Zeigt an, ob das Dropdown offen true oder geschlossen false ist
  • aria-haspopup="true" - Signalisiert, dass ein Untermenü existiert
  • role="menu" - Kennzeichnet die Liste als Menü
  • role="menuitem" - Kennzeichnet jeden Eintrag als Menüpunkt

Keyboard-Navigation

Ein gutes Dropdown sollte auch mit der Tastatur bedienbar sein:

  • Enter / Space: Dropdown öffnen/schließen
  • Escape: Dropdown schließen
  • Tab: Zum nächsten Element springen
  • Pfeiltasten: (optional) Zwischen Menüpunkten navigieren
Tipp

Das JavaScript im Klick-Dropdown oben enthält bereits die ESC-Taste und aktualisiert aria-expanded automatisch!

Best Practices

Do
  • Visuellen Indikator (Pfeil ▼) verwenden
  • Genug Klickfläche bieten (min. 44×44px)
  • Außerhalb-Klick zum Schließen
  • ESC-Taste zum Schließen
  • Hover + Klick kombinieren
  • ARIA-Attribute verwenden
Don't
  • Zu viele Verschachtelungen (max. 2 Ebenen)
  • Dropdown ohne visuellen Hinweis
  • Nur Hover auf Touch-Geräten
  • Zu kleine Klickflächen
  • Dropdown überlappt wichtige Inhalte
  • Animation zu langsam (max. 300ms)

Hover und Klick kombinieren

Die beste UX bietet oft eine Kombination: Auf Desktop öffnet Hover das Menü, auf Touch-Geräten der Klick.

CSS
/* Hover für Desktop */
@media (hover: hover) {
    .dropdown:hover .dropdown-menu {
        opacity: 1;
        visibility: visible;
    }
}

/* Klick funktioniert immer (via JavaScript) */
.dropdown.open .dropdown-menu {
    opacity: 1;
    visibility: visible;
}

Die Media Query @media (hover: hover) erkennt, ob das Gerät Hover unterstützt - Smartphones geben hier false zurück.

Mehr aus HTML

Tutorials werden geladen...