Warum ein dynamisches Inhaltsverzeichnis für langformatige Inhalte wichtig ist

Lange Artikel, Tutorials und Dokumentationsseiten können Leser überfordern, wenn die Navigation auf das manuelle Scrollen beschränkt ist. Ein dynamisches Inhaltsverzeichnis (TOC) löst dies, indem es eine anklickbare Gliederung bereitstellt, die automatisch den Abschnitt hervorhebt, den der Leser betrachtet. Dies verbessert die Benutzerfreundlichkeit, reduziert die Absprungraten und macht Ihren Inhalt für Benutzer zugänglicher, die schnell zwischen den Themen springen möchten. Im Gegensatz zu einem statischen TOC, der von Hand geschrieben wird, aktualisiert sich ein JavaScript-generierter TOC, wenn neue Abschnitte hinzugefügt werden, hält Links synchron mit Überschrift IDs und reagiert auf das Scrollverhalten in Echtzeit.

So wird ein technischer Leitfaden mit 30 Abschnitten viel leichter zu verdauen, wenn Leser ein Sidebar-Menü sehen, das ihren Fortschritt verfolgt. Das gleiche Prinzip gilt für Einzelseitenanwendungen, API-Dokumentationen oder sogar Blog-Posts mit mehreren Unterthemen. Durch die Implementierung eines dynamischen TOC geben Sie den Lesern die Kontrolle über ihr Leseerlebnis und reduzieren gleichzeitig die kognitive Belastung bei der Suche nach relevanten Teilen.

Kernkonzepte hinter einem dynamischen Inhaltsverzeichnis

Um einen dynamischen TOC zu erstellen, müssen Sie drei grundlegende Teile verstehen:

  • Semantische HTML-Struktur – jede Abschnittsüberschrift muss ein eindeutiges -Attribut haben, damit JavaScript darauf zielen kann.
  • DOM-Traversal und Manipulation – Ihr Skript scannt Überschriften, erstellt eine verschachtelte Liste von Links und fügt diese Liste einem Containerelement hinzu.
  • Scroll Eventhandling – ein effizienter Listener überprüft, welche Überschrift aktuell sichtbar ist und fügt dem entsprechenden TOC-Link eine Klasse hinzu.

Diese Stücke arbeiten zusammen, um einen TOC zu erzeugen, der sich nativ auf der Seite anfühlt, minimale serverseitige Logik erfordert und über moderne Browser funktioniert.

Schritt 1: Vorbereitung Ihrer HTML-Struktur

Bevor JavaScript ausgeführt wird, benötigen Sie zwei Dinge in Ihrem HTML:

Alleinstellungsmerkmale zu Überschriften zuweisen

Jede Überschrift, die im TOC (typischerweise , oder ) erscheinen sollte, muss eine eindeutige haben. Dies ist wichtig, da die TOC-Links Fragment-Identifikatoren (z. B. ) verwenden, um an die richtige Position zu scrollen.

<h2 id="introduction">Introduction</h2>
<p>...</p>
<h2 id="setup">Setting Up the Environment</h2>
<p>...</p>
<h3 id="installing-dependencies">Installing Dependencies</h3>
<p>...</p>
<h2 id="implementation">Implementation</h2>
<p>...</p>

Wenn Sie HTML nicht direkt ändern können, können Sie IDs aus Überschriftentext mit JavaScript (z. B. -Funktion) generieren, aber es ist einfacher, sie manuell oder mit einem statischen Site-Generator hinzuzufügen.

Erstellen Sie einen Container für den TOC

Platzieren Sie ein leeres Element (typischerweise ein oder ein ), wo der TOC erscheinen soll.

<nav id="table-of-contents" aria-label="Table of Contents"></nav>

Die verbessert die Zugänglichkeit, indem sie Bildschirmlesern einen beschreibenden Namen für die Navigationsregion gibt.

Schritt 2: Generieren des TOC mit JavaScript

Jetzt schreiben wir das JavaScript, das die Überschriften scannt und die Liste erstellt. Der folgende Ausschnitt erstellt eine flache Liste von Überschriften. Für einen fortgeschritteneren TOC, der Unterüberschriften enthält, benötigen Sie verschachtelte Listen, die wir später behandeln werden.

Basic Flat TOC Beispiel

const tocContainer = document.getElementById('table-of-contents');
const headings = document.querySelectorAll('h2');

// Bail early if there's no container or no headings
if (!tocContainer || headings.length === 0) return;

const ul = document.createElement('ul');
ul.setAttribute('role', 'list'); // accessibility enhancement

headings.forEach((heading, index) => {
 // Ensure the heading has an id; if not, generate one
 if (!heading.id) {
 heading.id = 'section-' + index;
 }
 const li = document.createElement('li');
 const a = document.createElement('a');
 a.textContent = heading.textContent;
 a.href = '#' + heading.id;
 a.setAttribute('data-section', heading.id); // useful for active detection
 li.appendChild(a);
 ul.appendChild(li);
});

tocContainer.appendChild(ul);

Key points:

  • Die Methode gibt eine statische zurück; sie funktioniert für Seiten, auf denen sich Überschriften nicht dynamisch ändern.
  • Fehlt einer Überschrift ein , so erzeugen wir automatisch einen Index, der defekte Links verhindert.
  • Wir fügen jedem Link ein -Attribut hinzu, um später eine einfachere Auswahl zu ermöglichen.

Handhabung verschachtelter Rubriken (H2, H3, H4)

Um verschachtelte Listen zu erstellen, verfolgen Sie die aktuelle und fügen Sie für seine Kinder ein.

const tocContainer = document.getElementById('table-of-contents');
const headings = document.querySelectorAll('h2, h3, h4');
if (!tocContainer || headings.length === 0) return;

const root = document.createElement('ul');
const stack = [{ element: root, level: 2 }]; // level refers to heading level

headings.forEach((heading) => {
 const level = parseInt(heading.tagName.substring(1), 10); // 'H2' -> 2
 if (!heading.id) heading.id = 'section-' + Math.random().toString(36).substr(2, 9);

 const li = document.createElement('li');
 const a = document.createElement('a');
 a.textContent = heading.textContent;
 a.href = '#' + heading.id;
 li.appendChild(a);

 // Pop stack until we reach the parent level
 while (stack.length > 0 && stack[stack.length - 1].level >= level) {
 stack.pop();
 }
 const parent = stack[stack.length - 1].element;
 parent.appendChild(li);

 // If next heading is lower, we need a nested list
 const nextLevel = headings.item(Array.from(headings).indexOf(heading) + 1);
 if (nextLevel && parseInt(nextLevel.tagName.substring(1), 10) > level) {
 const nestedUl = document.createElement('ul');
 li.appendChild(nestedUl);
 stack.push({ element: nestedUl, level: level });
 }
});

tocContainer.appendChild(root);

Dieser Algorithmus stellt sicher, dass jede Unterüberschrift unter ihrer übergeordneten Überschrift erscheint. Für die Produktion möchten Sie vielleicht die Logik verfeinern, um tiefe Stapel zu vermeiden und Randfälle zu behandeln (z. B. fehlende Überschriften).

Schritt 3: Hervorhebung des aktiven Abschnitts auf Scroll

Die Highlight-Mechanik lässt die Leser wissen, welchen Teil des Artikels sie gerade lesen. Die Idee ist, alle Überschriften zu durchblättern, denjenigen zu finden, der am nächsten am oberen Rand des Viewports liegt (mit einigen Versetzungen), und eine Klasse auf den entsprechenden TOC-Link anzuwenden.

Effizienter Scroll Listener

const tocLinks = document.querySelectorAll('#table-of-contents a');
const sections = Array.from(headings).map(h => ({
 id: h.id,
 top: h.offsetTop
}));

function updateActiveLink() {
 const scrollY = window.pageYOffset || document.documentElement.scrollTop;
 let currentId = '';

 // Iterate backwards for better performance
 for (let i = sections.length - 1; i >= 0; i--) {
 if (scrollY >= sections[i].top - 150) {
 currentId = sections[i].id;
 break;
 }
 }

 tocLinks.forEach(link => {
 link.classList.remove('active');
 if (link.getAttribute('href') === '#' + currentId) {
 link.classList.add('active');
 }
 });
}

// Throttle scroll events for performance
let ticking = false;
window.addEventListener('scroll', () => {
 if (!ticking) {
 window.requestAnimationFrame(() => {
 updateActiveLink();
 ticking = false;
 });
 ticking = true;
 }
});

Optimierungen:

  • Verwenden Sie , um Updates für den Browser-Farbzyklus zu begrenzen, wodurch Verzögerungen auf ausgelasteten Seiten vermieden werden.
  • Der Versatz von 150 Pixeln sorgt dafür, dass der Abschnitt ein wenig "aktiv" ist, bevor er ganz oben ankommt, was sich natürlicher anfühlt.
  • Das Iterieren von der letzten Überschrift rückwärts ist effizienter, da sich der aktive Abschnitt wahrscheinlich am Boden des sichtbaren Bereichs befindet.

Schritt 4: Hinzufügen von glattem Scrolling und Zugänglichkeit

Das glatte Scrollen macht das Springen zwischen den Abschnitten angenehm. Das können Sie mit CSS, aber auch über JavaScript für eine feinere Kontrolle erreichen.

// Add click handler on the TOC container to use smooth scrolling
tocContainer.addEventListener('click', (e) => {
 const link = e.target.closest('a');
 if (link && link.getAttribute('href').startsWith('#')) {
 e.preventDefault();
 const targetId = link.getAttribute('href').substring(1);
 const target = document.getElementById(targetId);
 if (target) {
 target.scrollIntoView({ behavior: 'smooth' });
 // Update the URL hash without causing a scroll jump
 history.pushState(null, '', '#' + targetId);
 }
 }
});

Verbesserungen der Zugänglichkeit:

  • Stellen Sie sicher, dass der TOC eine hat (z. B. “Tabelle der Inhalte”).
  • Fügen Sie zum aktiven Link hinzu: anstelle von Dies hilft Bildschirmlesern, den aktuellen Abschnitt anzukündigen.
  • Verwenden Sie und , wenn die Standard-Semantik / durch Styling überschrieben wird.

Schritt 5: Styling des dynamischen TOC

Während Styling nicht Teil der JavaScript-Logik ist, verstärkt ein gut gestylter TOC die Benutzerfreundlichkeit. Unten ist ein minimales CSS-Beispiel, das eine klebrige Positionierung für die Verwendung in der Sidebar hinzufügt:

#table-of-contents {
 position: sticky;
 top: 2rem;
 max-height: calc(100vh - 4rem);
 overflow-y: auto;
 border-left: 2px solid #ccc;
 padding-left: 1rem;
 font-size: 0.9rem;
}
#table-of-contents ul {
 list-style: none;
 padding: 0;
}
#table-of-contents li {
 margin-bottom: 0.25rem;
}
#table-of-contents a {
 color: #333;
 text-decoration: none;
}
#table-of-contents a.active {
 font-weight: bold;
 color: #007bff;
}
#table-of-contents a[aria-current="location"] {
 border-left: 2px solid #007bff;
 margin-left: -1rem;
 padding-left: calc(1rem - 2px);
}

Für ein responsives Design sollten Sie den TOC auf kleinen Bildschirmen verstecken und eine Umschalttaste hinzufügen oder in ein Select-Dropdown-Menü einfügen.

Erweiterte Erweiterungen

1. Debattieren von Größenänderungen

Wenn sich die Höhe des Viewports ändert (z. B. bei einer Änderung der mobilen Ausrichtung), können sich die -Werte der Überschriften verschieben.

let sections = [];
function recalcSections() {
 sections = Array.from(headings).map(h => ({
 id: h.id,
 top: h.offsetTop
 }));
}
let resizeTimer;
window.addEventListener('resize', () => {
 clearTimeout(resizeTimer);
 resizeTimer = setTimeout(recalcSections, 250);
});

2. Intersection Observer für die bildschirmbasierte Hervorhebung

Eine Alternative zu Scroll-Listern ist die API. Es ist performanter und einfacher zu verwalten.

const observer = new IntersectionObserver((entries) => {
 entries.forEach(entry => {
 if (entry.isIntersecting) {
 const id = entry.target.id;
 tocLinks.forEach(link => {
 link.classList.remove('active');
 if (link.getAttribute('href') === '#' + id) {
 link.classList.add('active');
 }
 });
 }
 });
}, { rootMargin: '-80px 0px -70% 0px' });

headings.forEach(h => observer.observe(h));

Dies feuert nur, wenn eine Überschrift in eine berechnete Zone eintritt oder diese verlässt, wodurch der Overhead reduziert wird.

3. Lazy Loading oder Dynamischer Inhalt

Wenn Ihr Artikel Abschnitte dynamisch lädt (z. B. über AJAX), müssen Sie den TOC regenerieren, nachdem neuer Inhalt angezeigt wird. Eine Möglichkeit ist die Verwendung eines MutationObservers auf dem Artikelcontainer und der Aufruf der TOC-Generierungsfunktion. Achten Sie jedoch darauf, dass Sie keine Einträge duplizieren.

Leistungsbetrachtungen

  • Vermeide schwere DOM-Abfragen innerhalb von Scroll-Handlern. Cache alle Selektoren einmal bei der Initialisierung.
  • Verwende passive Ereignis-Hörer für scroll: Dies verbessert die Scrolling-Leistung, insbesondere auf dem Handy.
  • Drosseln Sie nicht mit – ist effizienter, weil es mit der Renderschleife des Browsers synchronisiert wird.
  • [FLT:]] Minimieren und verschieben Sie das Skript , damit es das Seitenladen nicht blockiert.

Integration mit einem Static Site Generator (SSG) oder CMS

Wenn Sie einen statischen Site-Generator verwenden, können Sie den TOC mit eingebauten Funktionen (z. B. Eleventy-Sammlungen, Hugos ) vorrendern. Das dynamische Scroll-Highlighting erfordert jedoch weiterhin clientseitiges JavaScript. Der Vorteil eines serverseitigen TOC ist, dass es sofort verfügbar ist, noch bevor JavaScript läuft, was SEO und Zugänglichkeit unterstützt.

Bei einem CMS wie WordPress oder Directus können Sie den gleichen JavaScript-Ansatz verwenden, während Sie Überschriften-IDs im Inhalt speichern. Directus unterstützt beispielsweise benutzerdefinierte Schnittstellen, die IDs automatisch generieren. Sie können einen Hook erstellen, der auf Content Save läuft, um IDs zu Überschriften hinzuzufügen, und sich dann auf das Front-End-Javascript verlassen, um den TOC zu erstellen.

Externe Ressourcen für ein tieferes Verständnis:

Testen und Debuggen

  1. Stellen Sie sicher, dass jede Überschrift eine eindeutige hat. Duplicate IDs bewirken, dass der Browser nur zum ersten Match scrollt.
  2. Überprüfen Sie den TOC sowohl in hellen als auch in dunklen Themen, um sicherzustellen, dass der Linkkontrast den WCAG AA-Standards entspricht.
  3. Testen Sie mit Tastaturnavigation: Drücken Tab sollte zwischen TOC-Links wechseln und Enter sollte zum Abschnitt scrollen.
  4. Verwenden Sie die Registerkarte DevTools Performance des Browsers, um sicherzustellen, dass während des Scrollens kein Jank auftritt.
  5. Wenn der Artikel Bilder oder Iframes enthält, kann sich die nach dem Laden dieser Elemente ändern, eine Neuberechnungsfunktion auf aufrufen oder nachdem alle Bilder geladen wurden (z. B. ).

Mögliche Fallstricke und wie man sie vermeidet

  • Broken Links, wenn Überschriften IDs fehlen. Überprüfen Sie immer nach einem und generieren Sie einen, wenn Sie fehlen (verwenden Sie ein slugify-Dienstprogramm).
  • TOC flimmert während des Scrollens – verursacht durch zu viele Reflows.
  • Überlappende Abschnitte – das aktive Highlight könnte zu früh oder zu spät wechseln.
  • Nested TOC indentation issues – testet mit mehreren Ebenen (H2 → H3 → H4) und stellt sicher, dass die Liste korrekt dargestellt wird. Der oben genannte stapelbasierte Ansatz funktioniert, kann jedoch erweitert werden, um Lücken zu bewältigen (z. B. H2 direkt gefolgt von H4).
  • Performance on long pages – wenn Sie Hunderte von Überschriften haben, sollten Sie die Begrenzung des TOC auf nur H2 und H3 in Betracht ziehen oder virtuelles Scrollen für die Seitenleiste implementieren.

Schlussfolgerung

Durch die Zuweisung von IDs zu Überschriften, die Erstellung einer verschachtelten Liste von Links und die Hervorhebung des aktuellen Abschnitts basierend auf der Scroll-Position geben Sie den Lesern eine klare Roadmap. Die Codebeispiele in diesem Artikel bieten eine solide Grundlage, aber Sie können sie leicht erweitern - reibungsloses Scrollen hinzufügen, IntersectionObserver für eine bessere Leistung verwenden oder in Ihren vorhandenen Build-Prozess integrieren. Das Ergebnis ist eine professionellere Leseerfahrung, die die Zeit und Aufmerksamkeit der Benutzer respektiert, insbesondere auf inhaltsintensiven Websites wie Dokumentationsportalen, Tutorials oder Langformjournalismus.

Implementieren Sie den Ansatz, der am besten zu Ihrem Stack passt: reines JavaScript für einfache Websites oder ein Hybrid mit SSG für die anfängliche TOC-Struktur plus clientseitiges Hervorheben. Unabhängig von der Methode ist ein dynamisches TOC eine kleine Investition, die erhebliche Usability-Gewinne bringt.