Zum Inhalt springen
Frontend-Optimierung

Megamenü als Tempobremse: Navigation schlank ausliefern

Hunderte Kategorien in jeder Seite, oft doppelt: So messen Sie die Knoten Ihrer Navigation, begrenzen die Tiefe und laden tiefe Ebenen erst bei Bedarf.

21 Min. Lesezeit DOM-GrößeINPNavigationFrontend-Optimierung

Kurz und einfach erklärt

Viele Shops haben ein großes Menü. Es zeigt alle Bereiche und alle Unterbereiche. Dieses Menü steckt in jeder Seite. Das gilt auch dann, wenn man es gar nicht öffnet.

Das macht jede Seite schwerer. Der Browser muss mehr laden und mehr rechnen. Die Seite reagiert dann langsamer auf einen Klick.

Besser ist ein kleines Menü. Es zeigt nur die oberen Stufen. Die tiefen Stufen holt die Seite erst, wenn man das Menü öffnet.

Google soll trotzdem alle Bereiche finden. Darum zeigt jede Seite eines Bereichs ihre Unterbereiche als Link.

Wir messen Ihr Menü. Dann bauen wir es um. Danach prüfen wir, ob die Seite schneller ist.

In vielen Shops steckt der schwerste Teil einer Seite nicht im Inhalt, sondern darüber: im Megamenü. Jede Kategorie, jede Unterkategorie und oft noch eine dritte Ebene stehen als Link im HTML, auf der Startseite genauso wie auf jeder Produktseite. Häufig liegt derselbe Baum ein zweites Mal im Dokument, weil die mobile Schublade eine eigene Kopie bekommt. Der Besucher sieht davon nichts, solange er das Menü nicht öffnet. Der Browser muss es trotzdem laden, parsen, als DOM aufbauen und bei jeder Stiländerung mitprüfen. Die mittlere mobile Seite kommt auf 594 HTML-Elemente (Web Almanac 2024); ein Menü mit einigen Hundert Kategorien kommt bei Listenpunkt und Link je Eintrag allein schon in dieselbe Größenordnung. Dieser Beitrag zeigt, wie Sie die Knotenzahl der Navigation messen, welche Ebenen ins HTML gehören und wie tiefere Ebenen bei Bedarf nachkommen, ohne dass Suchmaschinen den Weg zu Ihren Kategorien verlieren. Dazu kommen ein einziges Markup für Desktop-Menü und Schublade, das Öffnen per CSS mit Absicht beim Überfahren und die Navigation als eigenes Cache-Fragment.

Das Wichtigste in Kürze

  • Die mittlere mobile Seite hat 594 HTML-Elemente (Web Almanac 2024). Ein Megamenü mit einigen Hundert Kategorien kommt bei Listenpunkt und Link je Eintrag allein in dieselbe Größenordnung, und zwar auf jeder Seite des Shops.
  • Zuerst messen: Elemente im nav gegen Elemente im body, die Zahl der Links und die Bytes des Menü-Markups. Liegt der Baum für Desktop und Schublade zweimal im Dokument, zählt er doppelt.
  • Die oberen zwei Ebenen bleiben als echte Links im HTML, die dritte kommt beim ersten Öffnen als Fragment nach. Weil die Google-Suche nicht mit der Seite interagiert (Google Search Central), verlinkt jede Kategorieseite ihre Unterkategorien.
  • Ein Markup für Desktop und Handy: CSS ordnet dieselbe Liste um, ein Button mit aria-expanded öffnet die Ebenen. Untermenüs schließen verzögert; das W3C-Beispiel nutzt dafür eine Sekunde (W3C WAI).
  • Überfahren zählt nicht zum INP (web.dev), die Arbeit dahinter kann aber den nächsten Klick verzögern. Mobil erreichen nur 69 Prozent der Unterseiten einen guten INP-Wert, Startseiten 80 Prozent (Web Almanac 2025).
  • Die Navigation ist auf allen Seiten gleich und gehört in ein eigenes Cache-Fragment. Shopware lädt Kopf- und Fußbereich seit Version 6.7 per ESI (Shopware); persönliche Teile wie der Warenkorbzähler kommen getrennt.

Warum die Navigation jede Seite schwerer macht

Eine Navigation gehört zu den wenigen Bauteilen, die auf jeder einzelnen Seite stehen. Ein Produkttext erscheint einmal, ein Kategorie-Teaser auf wenigen Seiten, das Menü aber auf Startseite, Listing, Produktseite, Suchergebnis und im Kundenkonto. Was dort zu viel steckt, zahlt jeder Seitenaufruf mit. Bei einem Shop mit tiefem Sortiment wächst die Hauptnavigation leise mit dem Katalog: Jede neue Unterkategorie wird automatisch ein weiterer Link im Kopf jeder Seite, ohne dass jemand die Vorlage anfasst. Wer nur die Startseite misst, sieht das oft nicht, weil dort Bilder und Slider die Diagnose bestimmen.

Die Kosten fallen an drei Stellen an. Erstens im HTML: Jede Zeile aus Listenpunkt und Link reist mit dem Dokument, wird komprimiert übertragen und im Browser wieder entpackt. Zur Einordnung: Die mittlere Startseite lädt am Desktop 18 KB HTML (Web Almanac 2024), ein Menü mit mehreren Hundert Kategorielinks ist daneben kein Randposten. Zweitens im DOM: Die mittlere mobile Seite hat 594 Elemente, im 90. Perzentil sind es 1.716 (Web Almanac 2024). Drittens in der Laufzeit: Je größer der Baum, desto teurer wird jede Stilberechnung und jedes Layout, auch wenn der Großteil der Knoten unsichtbar bleibt.

Die alten Schwellen des Lighthouse-Audits lagen bei einer Warnung ab etwa 800 und einem Fehler ab etwa 1.400 Knoten im body, und seit Lighthouse 13 ist das Audit in die Insight „Optimize DOM size“ gewandert (Chrome for Developers), was wir im Beitrag DOM-Größe reduzieren ausführlich einordnen.

Für das Megamenü ist eine andere Angabe aus derselben Dokumentation aufschlussreicher: Eine Stilneuberechnung gilt als groß, wenn sie mehr als 300 Elemente betrifft (Chrome for Developers). Genau in diese Größenordnung gerät ein Menü, das beim Öffnen eine Klasse am body oder am html-Element setzt, damit die Seite dahinter abgedunkelt wird oder das Scrollen stoppt. Dann muss der Browser unter Umständen große Teile der Seite neu bewerten, einschließlich aller versteckten Menüeinträge. Warum komplexe Selektoren diese Arbeit zusätzlich verteuern, beschreibt der Beitrag zur Style-Recalculation.

Bei der Reaktionszeit zeigt sich der Unterschied zwischen Einstieg und Tiefe. Mobil erreichen Startseiten zu 80 Prozent einen guten INP-Wert, Unterseiten nur zu 69 Prozent (Web Almanac 2025). Die Navigation ist nicht die einzige Ursache dafür, Listings mit Filtern und Produktseiten mit Galerien tragen ihren Teil bei. Sie ist aber ein Bauteil, das auf jeder dieser Unterseiten mitläuft, und darum ein Hebel, der überall gleichzeitig wirkt. Warum sich die Arbeit an Vorlagen mehr lohnt als an der Startseite allein, steht im Beitrag Vorlage statt Startseite.

Bevor etwas umgebaut wird, gehört die Navigation vermessen, und zwar auf einer typischen Kategorie- oder Produktseite, nicht nur auf der Startseite. Vier Werte reichen für den Anfang: die Zahl der Elemente im gesamten body, die Zahl der Elemente innerhalb jeder Navigation, die Zahl der Links darin und die Größe des Menü-Markups in Bytes. Das folgende Snippet liefert alle vier in der Konsole der Entwicklerwerkzeuge. Den Selektor passen Sie an Ihr Theme an; viele Shops haben mehr als ein nav-Element, etwa für Desktop, Schublade, Brotkrumen und Fußbereich.

nav-count.js
// In der Konsole einer typischen Kategorie- oder Produktseite ausführen
const total = document.body.querySelectorAll('*').length;
const navs = document.querySelectorAll('nav, [role="navigation"]');

for (const nav of navs) {
  const elements = nav.querySelectorAll('*').length;
  console.log(nav.getAttribute('aria-label') || nav.className || nav.tagName, {
    elements,
    links: nav.querySelectorAll('a[href]').length,
    hidden: [...nav.querySelectorAll('a[href]')].filter((a) => !a.checkVisibility({ visibilityProperty: true })).length,
    bytes: new Blob([nav.outerHTML]).size,
    share: (elements / total).toFixed(2),
  });
}
console.log('Elemente im body:', total);

Das Snippet zählt Elemente, nicht Knoten. Zu den Knoten gehören auch Text, Leerraum und Kommentare; Lighthouse nennt seine Schwellen in Knoten, gezählt hat das alte Audit aber Elemente („Total DOM Elements“), und der Leitfaden von web.dev arbeitet bewusst mit Elementen. Für den Vergleich ist das gleichgültig, solange Sie vor und nach dem Umbau gleich zählen. outerHTML misst das Markup unkomprimiert, also in der Form, die der Browser nach dem Entpacken verarbeiten muss. Die Spalte hidden zeigt, wie viele Links gerade nicht sichtbar sind; bei geschlossenem Menü ist das ein grober Wert für den Ballast, den jede Seite mitliefert.

Vier Befunde tauchen beim Messen besonders oft auf:

  • Zwei Bäume: Findet das Snippet zwei Navigationen mit fast gleicher Linkzahl, liegt das Menü doppelt im Dokument, einmal für den Desktop und einmal für die Schublade.
  • Versteckte Ebenen: Viele unsichtbare Links bei geschlossenem Menü zeigen, dass dritte und vierte Ebene mitgeliefert werden, obwohl sie nur auf Anforderung erscheinen.
  • Bilder im Menü: Teaserbilder in Megamenüs laden ohne loading="lazy" mit jeder Seite. Wie Sie solche Bilder in passender Breite ausliefern, zeigt der Beitrag zum Attribut sizes.
  • Inline-Daten: Manche Themes schreiben den Kategoriebaum zusätzlich als JSON in ein script-Element. Dann zahlt die Seite den Baum ein weiteres Mal, diesmal als Skriptdaten.

Im Netzwerkbereich sehen Sie dazu die Größe des HTML-Dokuments selbst, übertragen und entpackt. Wie Sie die erste Zeile im Wasserfall lesen und den Anteil des Dokuments an der Ladezeit einordnen, beschreibt der Beitrag Wasserfalldiagramm lesen. Für eine Interaktion im Labor lohnt ein Blick auf die Einträge „Recalculate Style“ im Performance-Bereich: Dort zeigt Chrome, wie viele Elemente eine Stilneuberechnung betroffen hat (web.dev). Öffnen Sie das Menü dafür mit gedrosselter CPU im Handyprofil, denn dort fällt jede überflüssige Neuberechnung am deutlichsten ins Gewicht.

Tiefe begrenzen: was ins HTML gehört

Die wichtigste Entscheidung ist keine technische, sondern eine redaktionelle: Wie viele Ebenen braucht ein Besucher, um sich zu orientieren? Für viele Sortimente reichen zwei Ebenen im ausgelieferten HTML. Die oberste Ebene nennt die Hauptbereiche, die zweite die Kategorien darunter. Alles Weitere ist Feinauswahl, die der Besucher ohnehin auf der Kategorieseite trifft, mit Filtern, Sortierung und Produktbildern. Ein Menü, das jede Unterkategorie auflistet, nimmt dieser Seite ihre Aufgabe ab und macht sie gleichzeitig auf jeder anderen Seite schwerer.

In Shopware steht die Tiefe des Hauptmenüs im Verkaufskanal unter „Hauptnavigations-Ebenen“. Laut Felddefinition im Quellcode bestimmt der Wert, wie viele Ebenen von Unterkategorien das Kategoriemenü der Storefront zeigt. Es lohnt sich, ihn nach jedem größeren Sortimentsausbau neu anzusehen. Eigene Themes und Erweiterungen können die Einstellung umgehen, wenn sie den Baum selbst laden; dann gehört die Vorlage geprüft, nicht nur die Einstellung. In unserer Shopware-Performance gehört dieser Blick in die Vorlagen zum festen Ablauf.

Welche Kategorien in die zweite Ebene gehören, entscheiden die Zugriffsdaten, nicht das Organigramm. Kategorien, die kaum jemand über das Menü aufruft, wandern auf die Kategorieseite ihres Bereichs. Ein Link „Alle anzeigen“ am Fuß jeder Spalte führt zur übergeordneten Kategorieseite und ersetzt eine lange Liste, die ohnehin kaum jemand bis zum Ende liest. Für Besucher ist das kein Verlust: Die Kategorieseite zeigt die Unterkategorien mit Bild, Produktzahl und Filtern, das Menü nur ihren Namen.

Ein Sonderfall sind Aktionen und Saisonthemen. Sie landen gern als zusätzliche Spalte mit Bild im Megamenü und bleiben dort, lange nachdem die Aktion vorbei ist. Ein fester Platz mit genau einem Teaser, der redaktionell getauscht wird, hält die Navigation stabil. Dasselbe gilt für Herstellerlisten: Eine Spalte mit allen Marken des Sortiments gehört auf eine eigene Markenseite, nicht in den Kopf jeder Produktseite.

Tiefere Ebenen bei Bedarf nachladen

Was nicht ins HTML gehört, muss nicht verschwinden. Die dritte Ebene kann als HTML-Fragment nachkommen, sobald der Besucher Interesse an einem Hauptpunkt zeigt. web.dev beschreibt genau dieses Vorgehen: Teile der Seite, die beim Start nicht sichtbar sind, zunächst weglassen und erst ergänzen, wenn der Besucher mit dem Bereich interagiert (web.dev). Der Vorteil wirkt doppelt. Das erste Dokument ist leichter und wird schneller dargestellt, und Interaktionen während des Ladens konkurrieren mit weniger Arbeit um den Hauptthread.

Das Fragment liegt sinnvollerweise unter einer eigenen, statisch cachebaren Adresse je Hauptbereich, etwa /navigation/werkzeug.html. Es wird geladen, wenn der Zeiger den Hauptpunkt erreicht, der Punkt den Fokus bekommt oder auf dem Handy die Ebene geöffnet wird. Ein zweiter Aufruf kommt aus dem Browser-Cache oder aus dem Speicher des Skripts. Wichtig ist eine sichtbare Rückmeldung, falls das Fragment einmal länger braucht: Laufende Netzwerkanfragen zählen nicht zum INP, verlängern aber die gefühlte Wartezeit, weshalb web.dev einen Ladehinweis empfiehlt (web.dev).

nav-fragment.js
// Dritte Ebene beim ersten Interesse laden, jede Ebene nur einmal
const pending = new WeakMap();

function loadLevel(item) {
  if (pending.has(item)) return pending.get(item);
  const panel = item.querySelector('.nav-panel');
  panel.setAttribute('aria-busy', 'true');
  const job = fetch(item.dataset.fragment)
    .then((res) => (res.ok ? res.text() : Promise.reject(res.status)))
    .then((html) => panel.insertAdjacentHTML('beforeend', html))
    .catch(() => pending.delete(item)) // beim nächsten Interesse neu versuchen
    .finally(() => panel.removeAttribute('aria-busy'));
  pending.set(item, job);
  return job;
}

for (const item of document.querySelectorAll('.nav-item[data-fragment]')) {
  for (const type of ['pointerenter', 'focusin', 'click']) {
    item.addEventListener(type, () => loadLevel(item));
  }
}

Die obere und die zweite Ebene stehen weiterhin vollständig als Links im HTML. Das Skript ergänzt nur, es ersetzt nichts. Fällt es aus oder ist das Netz langsam, bleibt jede Kategorie über ihren Hauptpunkt und die Kategorieseite erreichbar. Das Fragment selbst enthält nur Markup ohne Skript und ohne Inline-Stile, damit es sich ohne weitere Arbeit in das vorhandene Panel einfügt.

Shopware nutzt dieses Muster selbst: Die mobile Schublade der Storefront holt ihre Ebenen beim Antippen über eine eigene Route nach, statt den ganzen Baum ins Dokument zu schreiben. Seit Version 6.7.3.0 hält Shopware außerdem die Standard-Kategorieebenen der Hauptnavigation im Cache, damit sie nicht bei jedem Aufruf neu geladen und aufbereitet werden (Shopware). Für eigene Themes heißt das: zuerst prüfen, ob sie diese Wege nutzen oder den vollständigen Baum doch wieder in die Vorlage holen.

Was Suchmaschinen weiterhin finden müssen

Der häufigste Einwand gegen schlanke Menüs ist die Sorge um die Auffindbarkeit: Wenn die dritte Ebene nicht mehr im HTML jeder Seite steht, findet Google sie dann noch? Die Antwort hängt davon ab, ob es außer dem Menü einen zweiten Weg gibt. Google kann einen Link in der Regel nur verfolgen, wenn er ein <a>-Element mit href-Attribut ist (Google Search Central). Und Inhalte, die erst nach einer Aktion wie Klicken oder Scrollen geladen werden, erfasst die Google-Suche auf diesem Weg nicht, weil sie nicht mit der Seite interagiert (Google Search Central).

Ein Fragment, das beim Überfahren nachkommt, bleibt für den Crawler also unsichtbar. Das ist kein Problem, solange jede Unterkategorie auf ihrer übergeordneten Kategorieseite als normaler Link steht und jede Seite Brotkrumen bis zur Startseite führt. Google formuliert die Regel schlicht: Jede Seite, auf die es Ihnen ankommt, sollte von mindestens einer anderen Seite der Website verlinkt sein (Google Search Central). Brotkrumen zeigen die Lage einer Seite in der Hierarchie, und als BreadcrumbList ausgezeichnet werden sie für die Suche lesbar (Google Search Central).

Damit ist die Navigation nicht mehr der einzige Weg zu den Kategorien, sondern einer von mehreren. Für die Barrierefreiheit gilt dasselbe: Das W3C rät, die Einträge eines Untermenüs zusätzlich auf der Seite des übergeordneten Menüpunkts zu wiederholen, weil Menschen mit eingeschränkter Feinmotorik Ausklappmenüs oft schwer bedienen können (W3C WAI). Eine Kategorieseite, die ihre Unterkategorien als Kacheln oder Liste zeigt, löst beide Aufgaben zugleich. Eine Zusage über Rankings ist das nicht; es sichert nur, dass kein Ziel allein am Menü hängt.

Ein zweiter Punkt betrifft die Größe. Für die Google-Suche liest Googlebot die ersten 2 MB einer unterstützten Datei (Google Search Central), und diese Grenze gilt für die unkomprimierten Daten (Google Search Central). In der Regel liegen Shopseiten weit darunter. Weil die Navigation aber am Anfang des Dokuments steht, verbraucht ein aufgeblähtes Menü dieses Budget zuerst, vor Produkttext und Bewertungen weiter unten. Wer ohnehin große Seiten ausliefert, etwa lange Listings mit vielen Varianten, sollte die Summe aus Menü und Inhalt deshalb einmal unkomprimiert messen.

Ein Markup für Desktop und Schublade

Viele Themes bauen die Navigation zweimal: als Megamenü für breite Bildschirme und als Liste in der mobilen Schublade. Beide Kopien stehen in jedem Dokument, eine davon ist jeweils versteckt. Auf dem Handy zahlt der Besucher damit für ein Desktop-Menü, das er dort gar nicht zu sehen bekommt, und am Desktop für eine Schublade, die dort geschlossen bleibt. Wer die Navigation misst, erkennt diesen Fall an zwei Bäumen mit fast gleicher Linkzahl.

Die Alternative ist eine einzige Liste, die per CSS je nach Breite anders angeordnet wird: am Desktop als waagrechte Leiste mit Panels, auf dem Handy als senkrechte Liste mit aufklappbaren Gruppen. Die Struktur bleibt dieselbe verschachtelte Liste aus ul, li und a; nur Darstellung und Bedienelement unterscheiden sich. Der Link eines Hauptpunkts führt zur Kategorieseite, ein eigener Button daneben öffnet das Panel.

main-nav.html
<nav class="main-nav" aria-label="Hauptnavigation">
  <button type="button" class="nav-toggle" aria-expanded="false" aria-controls="nav-list">
    Menü
  </button>
  <ul id="nav-list" class="nav-list">
    <li class="nav-item" data-fragment="/navigation/werkzeug.html">
      <a href="/werkzeug/">Werkzeug</a>
      <button type="button" class="nav-open" aria-expanded="false" aria-controls="panel-werkzeug">
        <span class="visually-hidden">Untermenü Werkzeug</span>
      </button>
      <div class="nav-panel" id="panel-werkzeug">
        <ul>
          <li><a href="/werkzeug/elektrowerkzeug/">Elektrowerkzeug</a></li>
          <li><a href="/werkzeug/handwerkzeug/">Handwerkzeug</a></li>
          <li><a href="/werkzeug/">Alle in Werkzeug</a></li>
        </ul>
      </div>
    </li>
  </ul>
</nav>

Wer in der Schublade ganz ohne eigenes Skript auskommen möchte, kann die Gruppen auch als details und summary auszeichnen. Das Element gilt seit dem 15. Juli 2022 als weitgehend verfügbar (Web Features Explorer). Mehrere details mit demselben Attribut name schließen sich gegenseitig, sodass jeweils nur eine Gruppe offen ist; das läuft seit dem 3. September 2024 in allen großen Browsern (Web Features Explorer). Am Desktop passt details weniger gut, weil es sich nicht beim Überfahren öffnet. Für ein gemeinsames Markup ist die Variante mit Link und Button darum meist die robustere.

Wichtig für die Bedienung mit Tastatur: Untermenüs sollen sich nicht schon öffnen, wenn jemand mit der Tabulatortaste durch die Hauptpunkte geht, sonst muss er sich durch jeden Untereintrag arbeiten, um den nächsten Hauptpunkt zu erreichen (W3C WAI). Ein Button mit aria-expanded neben dem Link löst das: Der Link führt zur Kategorieseite, der Button öffnet das Panel. Wie Dialoge und Popover ohne eigenes Skript über command und commandfor gesteuert werden, zeigt der Beitrag Dialog und Popover direkt in HTML.

Öffnen per CSS, Absicht beim Überfahren erkennen

Viele Megamenüs hängen an einer Bibliothek, die Mausbewegungen auswertet, Panels positioniert, Zeitgeber setzt und Klassen umschaltet. Für das Öffnen beim Überfahren braucht es das meist nicht. CSS kann ein Panel zeigen, solange der Zeiger auf dem Hauptpunkt oder dem Panel liegt, und es kann Öffnen und Schließen verzögern. Das bildet die Absicht beim Überfahren ab: Wer mit der Maus quer über die Leiste zum Suchfeld fährt, soll nicht jedes Panel auf dem Weg aufklappen lassen, und wer schräg vom Hauptpunkt ins Panel zieht, soll es nicht unterwegs verlieren.

main-nav.css
/* Desktop mit Maus: Öffnen leicht verzögert, Schließen deutlich später */
@media (min-width: 64em) and (hover: hover) {
  .nav-item { position: relative; }
  .nav-panel {
    position: absolute;
    top: 100%;
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.15s ease 0.25s, visibility 0s linear 0.4s;
  }
  .nav-item:hover > .nav-panel,
  .nav-item.is-open > .nav-panel {
    visibility: visible;
    opacity: 1;
    transition-delay: 0.12s;
  }
}

Das W3C-Tutorial zu Ausklappmenüs verzögert das Schließen mit einem Zeitgeber, damit ungenaue Mausbewegungen das Menü nicht sofort zuklappen; im Beispiel ist es eine Sekunde (W3C WAI). In CSS übernehmen das die verzögerten Übergänge auf opacity und visibility: Das Panel blendet erst nach einer Viertelsekunde aus und bleibt bis dahin bedienbar. Die Werte im Beispiel oben sind Startpunkte für eigene Tests, keine Vorgabe. Die Bedingung (hover: hover) sorgt dafür, dass Touch-Geräte dieses Verhalten gar nicht erst bekommen; dort öffnet der Button. Animiert wird nur opacity, nicht Höhe oder Position, damit kein Layout neu berechnet werden muss.

Inhalte, die beim Überfahren erscheinen, müssen laut Erfolgskriterium 1.4.13 der WCAG 2.2 drei Bedingungen erfüllen: Sie lassen sich schließen, ohne Zeiger oder Fokus zu bewegen, der Zeiger kann über den neuen Inhalt fahren, ohne dass er verschwindet, und sie bleiben sichtbar, bis der Auslöser wegfällt (W3C). Ein Panel, das direkt am Hauptpunkt anschließt und mit Escape schließt, erfüllt das. Eine Lücke von wenigen Pixeln zwischen Leiste und Panel lässt es dagegen beim Hinüberfahren zuklappen. Für Escape und den Zustand des Buttons genügen wenige Zeilen Skript am nav-Element; das ist kein Vergleich zu einer Menübibliothek.

Mit dem Attribut interestfor gibt es inzwischen einen eingebauten Weg, Interesse per Überfahren, Fokus oder langem Drücken zu erkennen. Er läuft aber bisher nur in Chrome und Edge ab Version 142, nicht in Firefox und Safari (Web Features Explorer). Für ein Hauptmenü ist er darum eine Ergänzung für später, keine Grundlage.

Für den INP-Wert gilt eine Besonderheit: Überfahren, Zoomen und Scrollen zählen nicht als Interaktion, gemessen werden Klicks, Tippen und Tastendrücke (web.dev). Ein Megamenü, das beim Überfahren schwere Arbeit startet, taucht im INP darum nicht direkt auf. Es kann aber den Klick verzögern, der unmittelbar danach kommt, wenn der Hauptthread dann noch beschäftigt ist. Auf dem Handy ist der Fall eindeutig: Dort öffnet ein Tippen das Menü, und genau dieses Tippen wird gemessen.

Darum lohnt es sich, den Zustand am Menü zu halten und nicht am body. Eine Klasse am Listenpunkt betrifft in der Regel nur dessen Teilbaum, eine Klasse am body kann Selektoren auf der ganzen Seite neu auswerten lassen. Wer beim Öffnen die Seite dahinter abdunkeln möchte, legt dafür ein eigenes Element über den Inhalt, statt eine Regel am body umzuschalten. Und wer das Scrollen der Seite hinter der Schublade sperren muss, setzt die Sperre einmal und nicht bei jeder Bewegung neu.

Wirkung auf INP und HTML-Größe nachweisen

Der Umbau ist erst fertig, wenn er gemessen ist, und zwar mit denselben Werten wie vorher. Für das HTML sind das die Bytes des Dokuments und der Anteil der Navigation daran, für das DOM die Zahl der Elemente auf einer typischen Unterseite. Für die Reaktion zählt INP: Gut ist ein Wert bis 200 Millisekunden, schlecht ein Wert über 500 Millisekunden (web.dev). Weil INP aus Felddaten kommt, braucht die Bewertung Zeit; im Labor ergänzen die Einträge „Recalculate Style“, wie viele Elemente das Öffnen des Menüs betroffen hat.

  • Dokumentgröße: Bytes des HTML-Dokuments auf einer Kategorie- und einer Produktseite, übertragen und entpackt.
  • Elemente: Zahl im body und Zahl in jeder Navigation, mit demselben Snippet gezählt.
  • Öffnen im Labor: Dauer der Stilneuberechnung und Zahl betroffener Elemente beim Öffnen des Menüs, im Handyprofil mit gedrosselter CPU.
  • INP im Feld: Wert der Unterseiten getrennt von der Startseite, beobachtet über mehrere Wochen.
  • Erreichbarkeit: Jede Kategorie der dritten Ebene ist von ihrer übergeordneten Kategorieseite verlinkt, geprüft per Crawl ohne Skriptausführung.

Wie Sie INP-Werte im Feld aufschlüsseln und lange Aufgaben finden, beschreibt der Beitrag INP optimieren. Wie sich die Werte in die übrigen Core Web Vitals einfügen, prüfen wir bei jedem Umbau mit, damit ein leichteres Menü nicht an anderer Stelle einen Layoutsprung erzeugt, etwa wenn das Fragment nachträglich die Höhe eines Panels verändert.

Ein Panel, das schon im DOM liegt, aber selten geöffnet wird, lässt sich zusätzlich vom Rendering ausnehmen. Wann content-visibility hilft und wann es Panels mit eigener Positionierung stört, steht im Beitrag content-visibility. Für das Megamenü ist das die zweite Wahl: Knoten, die gar nicht erst im Dokument stehen, kosten weder Übertragung noch Speicher.

Die Navigation als eigenes Cache-Fragment

Die Navigation ist auf allen Seiten eines Shops gleich, zumindest für alle Besucher einer Sprache und eines Verkaufskanals. Trotzdem wird sie in vielen Systemen bei jedem Seitenaufbau neu berechnet: Kategorien laden, Sichtbarkeit prüfen, Links erzeugen, Markup schreiben. Das kostet Serverzeit vor dem ersten Byte und bindet die Navigation an die Lebensdauer jeder einzelnen Seite. Ändert sich ein Preis, verfällt mit der Produktseite auch das Menü, obwohl es sich nicht geändert hat.

Besser ist ein eigenes Fragment mit eigener Lebensdauer. Shopware geht diesen Weg seit Version 6.7: Kopf- und Fußbereich werden per ESI geladen (Shopware), und das erlaubt, sie getrennt vom Rest der Seite zu cachen (Shopware). Ändert sich ein Produktpreis, muss die Navigation nicht neu entstehen; ändert sich eine Kategorie, wird das Fragment ungültig, ohne dass jede Seite allein wegen des Menüs neu aufgebaut werden muss. In anderen Systemen erreichen Sie dasselbe mit einem serverseitigen Include, das den Menüteil getrennt zwischenspeichert, oder mit einem eigenen Cache-Eintrag, der beim Speichern einer Kategorie gelöscht wird.

Für die Fragmente der dritten Ebene ist die Lage noch einfacher. Sie sind für alle Besucher gleich und lassen sich als statische Dateien mit langer Cachedauer ausliefern, wenn ihre Adresse eine Version trägt, die sich mit dem Kategoriebaum ändert. Ein neuer Baum bekommt eine neue Adresse, alte Kopien laufen einfach aus. Der Server muss dann für ein geöffnetes Menü keine einzige Datenbankabfrage mehr ausführen.

Heikel wird es, wenn die Navigation persönliche Teile enthält: den Namen im Kontomenü, die Zahl im Warenkorb, eine Kundengruppe mit eigenen Kategorien. Steht das im selben Fragment, zerfällt der Cache in viele kleine Varianten. Solche Teile kommen getrennt nach oder werden im Browser ergänzt. Warum schon ein einzelnes Cookie die Trefferquote zerlegen kann, beschreibt der Beitrag Ein Cookie zerlegt den Cache; welche Cache-Schichten im Shop zusammenspielen, erklären wir auf der Seite Caching-Strategien.

Der Umbau in sechs Schritten

  1. Messen: Elemente, Links und Bytes der Navigation auf einer typischen Kategorie- und Produktseite erfassen, dazu den INP der Unterseiten als Ausgangswert.
  2. Tiefe festlegen: Anhand der Zugriffsdaten entscheiden, welche Kategorien in die zweite Ebene gehören; alles darunter wandert auf die Kategorieseiten.
  3. Zweiten Weg sichern: Jede Kategorieseite verlinkt ihre Unterkategorien als normale Links, Brotkrumen führen bis zur Startseite.
  4. Eine Liste bauen: Desktop-Menü und Schublade auf dasselbe Markup zurückführen und die doppelte Kopie entfernen.
  5. Nachladen und öffnen: Dritte Ebene als versioniertes Fragment, Öffnen per CSS mit Verzögerung, Button mit aria-expanded für Tastatur und Touch.
  6. Cachen und nachmessen: Navigation als eigenes Fragment cachen, persönliche Teile trennen und dieselben Werte erneut messen.

Die meisten dieser Schritte sind Vorlagenarbeit, keine neue Technik. Der Aufwand steckt im Abgleich: Welche Kategorie braucht welchen Weg, welche Erweiterung schreibt eigene Links ins Menü, welche Stelle im Theme liest den Baum ein zweites Mal. In unserer Frontend-Optimierung gehen wir diese Liste für Ihren Shop durch, setzen den Umbau um und messen Dokumentgröße, Elementzahl und INP vor und nach der Änderung. Wer zuerst wissen möchte, wo der eigene Shop steht, beginnt mit einer technischen Analyse.

Quellen und Dokumentation

Dieser Artikel basiert auf Daten aus: HTTP Archive Web Almanac 2024 (Kapitel Markup und Page Weight); HTTP Archive Web Almanac 2025 (Kapitel Performance); Chrome for Developers (Avoid an excessive DOM size, Optimize DOM size); Lighthouse (Quellcode des alten DOM-Audits); web.dev (Interaction to Next Paint, How large DOM sizes affect interactivity); Google Search Central (Link best practices, Lazy-loaded content, What Is Googlebot, Breadcrumb); W3C WAI (Fly-out Menus); W3C (WCAG 2.2); Web Features Explorer (<details>, Mutually exclusive <details>, Interest invokers); Shopware (Upgrade-Hinweise 6.7.0.0 und 6.7.3.0, Quellcode der Storefront).

Verwandte Artikel

Frontend-Optimierung

Zu große Bilder trotz srcset: sizes richtig setzen

Trotz srcset lädt der Browser die große Bilddatei? Meist fehlt sizes oder passt nicht mehr zum Raster. Wie der Browser wählt, wie Sie sizes ableiten und prüfen.

18 Min. Lesezeit
Core Web Vitals & Messung

Wasserfalldiagramm lesen: was jede Zeile über Tempo verrät

Wasserfalldiagramm lesen: wie es geordnet ist, was die Phasen eines Balkens zeigen und welche sechs Muster über mehrere Zeilen typische Bremsen verraten.

20 Min. Lesezeit
Server & Hosting

WordPress trotz Cache langsam: WP-Cron und admin-ajax

Seiten-Cache aktiv, WordPress trotzdem träge? WP-Cron, Heartbeat und admin-ajax gehen am Cache vorbei und belegen PHP-Worker. So messen und entlasten Sie sie.

19 Min. Lesezeit