Tutorial
13. Februar 2024

Dynamisches Inhaltsverzeichnis in Webflow erstellen (Rich Text + CMS)

Webflow Experte - Sönke Sproll lacht
Sönke Sproll
Webflow Experte
Dynamisches Inhaltsverzeichnis in Webflow erstellen (Rich Text + CMS)
Inhaltsverzeichnis

Wenn Du regelmäßig längere Blogbeiträge verfasst, weißt Du sicherlich, wie schnell sie unübersichtlich werden können. Ein Inhaltsverzeichnis kann hier Abhilfe schaffen. Nicht nur Google bevorzugt Webseiten, die ein solches Verzeichnis bieten – es verbessert auch erheblich die Nutzererfahrung. In Webflow gibt es verschiedene Methoden, ein Inhaltsverzeichnis zu erstellen. Ich zeige Dir eine effektive Methode, die Dein Inhaltsverzeichnis automatisch basierend auf Deiner Überschriftenhierarchie generiert. Das bedeutet, nach der einmaligen Einrichtung musst Du Dich theoretisch nie wieder um Dein Inhaltsverzeichnis kümmern – es aktualisiert sich von selbst.

Hier gehts direkt zum Webflow-Clonable: Dynamisches Inhaltsverzeichnis in Webflow*

Basiert auf dem Konzept und Code und von Virtual Entity: Automatisches Inhaltsverzeichnis, das bereitgestellte Tutorial wird von mir erweitert, um die Implementierung noch schneller und Entwickler-freundlicher zu machen.

Aufbau in Webflow

Um das Inhaltsverzeichnis funktional zu machen, brauchst Du ein Rich Text Element in Webflow, wessen Inhalte auch aus dem CMS gezogen werden können. Gebe diesem Element die ID ‘content’.

Darüber hinaus brauchen wir einen Div-Block, welcher unser späteres Inhaltsverzeichnis beinhalten soll. Gebe diesem die ID ‘toc-wrapper’, was für die Funktionalität später wichtig wird. In diesem Div-Block solltest Du ein Custom Code / Embed Element einfügen. Hier fügen wir später unseren Code ein, welcher die ganze Funktionalität beinhaltet. In unserem Div ‘toc-wrapper’ sollte ebenso ein Listen Element mit der Klasse ‘toc_uolist’ eingefügt werden. Füge dann zwei Listenelemente hinzu mit der Klasse ‘toc_item’, in diesem sollte jeweils ein Text Link mit der Klasse ‘toc_link’ sein. Gebe einem der beiden Text Links die zusätzliche Klasse ‘toc_is-active’. Dieses Element signalisiert dem Nutzer, wo im Blogbeitrag er sich gerade befindet. In meinem Fall lasse ich ‘toc_link toc_is-active’ unterstreichen, Du kannst aber auch Farbe, Größe oder Schriftart anpassen.

Unsere Klasse ‘toc_uolist’ mit ihren Elementen wird später die Grundlage für unser Inhaltsverzeichnis. Sobald die Funktionalität steht, kannst Du dieses später 100 % nach Deinen eigenen Wünschen und Designvorgaben stylen.

Verstecke als Letztes die Liste ‘toc_uolist’, indem Du Display auf None setzt. Wir laden später die Elemente mit unserem Code in unser Design.

Code Snippet und Einstellungen

Füge folgendes Code Snippet in das Embed Element ein:


<div>
    <style>
        .toc_item {
            list-style-type: none;
        }
    </style>
    <script>
        let contentID = "content"; // ID of content
        let tocID = "toc-wrapper"; // ID to TOC element, if empty use parent div
        let headingLevels = ["h2", "h3"]; // Define the different levels
        let offset_size = "6rem"; // Define the offset of the anchor on scroll
        let toc_container;
				let anchors = [];

        if (tocID == "") {
            var scriptTag = document.getElementsByTagName('script');
            scriptTag = scriptTag[scriptTag.length - 1];
            toc_container = scriptTag.parentNode;

        }

        window.addEventListener('load', () => {

            let content = document.getElementById(contentID);
            if (tocID != "") {
                toc_container = document.getElementById(tocID);
            }
            var toc = document.createElement('ul');
            toc.className = "toc_uolist";
            toc_container.appendChild(toc);
            let sub_eles = content.getElementsByTagName('*');
            var nesting = [toc];
            var hadH2 = false;
            for (const ele of sub_eles) {
            		if (ele.tagName.toLowerCase() == "h2"){
                	hadH2 = true;
                }
                var i;
                for (i = 0; i < headingLevels.length; i++) {
                    var level = headingLevels[i];
                    if ((level[0] == '.' && ele.className.toLowerCase() == level.slice(1).toLowerCase()) ||
                        ele.tagName.toLowerCase() == level.toLowerCase()) {
                        break;
                    }
                }
                if (i < headingLevels.length) {
                    while (nesting.length - 1 > i)
                        nesting.pop()
                    while (nesting.length - 1 < i) {
                        let nest = document.createElement('ul');
                        nest.className = "toc_uolist";
                        nesting[nesting.length - 1].appendChild(nest);
                        nesting.push(nest);
                    }
                    let toc_ele = document.createElement('a');
                    let anchor = document.createElement('a');
										anchors.push([anchor, toc_ele]);
										for (var i = 0; i < ele.innerText.length; i++) {
				                let germanReplacements = { "ü": "ue", "Ü": "Ue", "Ä": "Ae", "ä": "ae", 'Ö': "Oe", "ö": "oe", "ß": "ss" }
				                if (/[a-zA-Z0-9]/.test(ele.innerText[i])) {
				                    anchor.id += ele.innerText[i];
				                } else if (ele.innerText[i] == " ") {
				                    anchor.id += "-";
				                } else if (ele.innerText[i] in germanReplacements) {
				                    anchor.id += germanReplacements[ele.innerText[i]];
				                }
				            }
                    anchor.style = "top:-" + offset_size + "; position: relative;"
                    ele.appendChild(anchor);
                    toc_ele.href = "#" + anchor.id;
                    toc_ele.innerText = ele.innerText;
                    toc_ele.className = "toc_link";
                    var item = document.createElement('li');
                    item.appendChild(toc_ele);
                    item.className = "toc_item";
                    nesting[nesting.length - 1].appendChild(item);
                }

            }
            if (!hadH2){
            	toc.style.display = "None";
              let toHide = document.getElementsByClassName("toc_inner-wrapper");
              for (var i = 0; i < toHide.length; i++){
              	toHide[i].style.display = "none";
              }
            }
        });
				window.addEventListener('scroll', () => {
				    let cur_active;
				    let cur_value;
				    for (var i = 0; i < anchors.length; i++) {
				        anchors[i][1].classList.remove('toc_is-active');
				        var pos = anchors[i][0].getBoundingClientRect().top;
				        if (pos < window.innerHeight / 2) {
				            if (!cur_value || cur_value < pos) {
				                cur_value = pos;
				                cur_active = anchors[i][1];
				            }
				        }
				    }
				    console.log(cur_active.href);
				    if (cur_active) {
				        cur_active.classList.add('toc_is-active');
				    }
				});
    </script>
</div>

Funktionsweise / Einstellungen

Die Variable ‘headingLevels’ definiert die Elemente, welche im Inhaltsverzeichnis als Punkt aufgeführt werden sollen. Standardgemäß sind h2 und h3 Elemente als Wert hinterlegt, diese kannst Du abändern oder ergänzen zum Beispiel mit h4’s.

Mit offset_size kannst den Offset des Ankers beim Scrollen auf die jeweilige Headline definieren, je größer die Zahl, desto mehr Platz ist vor der Headline.

Jetzt mit Webflow starten*

Mit Sternchen * markierte Links sind Affiliate-Links.

Bereit für ein erfolgreiches Webflow Projekt?

Erstgespräch
Pfeil nach oben Icon
Webflow Experte - Sönke Sproll

Noch kein Webflow Experte?

Erhalte exklusiven Zugang zu Fachwissen, Insider-Content und Ressourcen über Webflow in unserem Newsletter.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Alter Mann als Webflow Experte

Noch kein
Webflow Experte?

Erhalte exklusiven Zugang zu Fachwissen, Insider-Content und Ressourcen über Webflow in unserem Newsletter.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.