Willkommen beim WP Wegerl.at 'Lesemodus'!
Entspanntes Lesen und spannende Artikel warten auf dich.
Entdecke unsere besten Beiträge und genieße den Lesemodus.
WP Wegerl.at: Einzigartige Designs, optimiert für das Nutzererlebnis.
Blume, Biene, Inhalt
smilies.4-user.de

Inhaltsverzeichnis (TOC) –
Plug-In Easy Table of Content

Werbung

Der Classic-Editor: Vertraut und zuverlässig –
Ihr bewährter Begleiter.  Info


Erleben Sie den Classic Editor neu!
(Bilder von pixelcreatures)


Viele Nutzer schätzen die vertraute Umgebung des Classic-Editors, die eine einfache und schnelle Bearbeitung ermöglicht.




Werbung

Mit dem Advanced Editor Tools auf das nächste Level –
Mehr Funktionen, mehr Möglichkeiten.


Classic Editor + Advanced Editor Tools
= Ihr Erfolgsrezept


Der Advanced Editor erweitert den Funktionsumfang des Classic-Editors und ermöglicht es, Inhalte noch effektiver zu bearbeiten.




Werbung

Einfach und intuitiv –
Der Classic-Editor für alle. Info


Classic Editor & Advanced Editor Tools
Erleben Sie es.


Der Classic-Editor zeichnet sich durch Stabilität und Zuverlässigkeit aus, was für professionellen Anwender von Bedeutung ist.




Werbung

Mehr schaffen in weniger Zeit –
Der Advanced Editor für kreative Köpfe.


Optimieren Sie Ihre Bearbeitung:
Advanced Editor Tools


Mit dem Advanced Editor können Designer und
Content Creatoren kreative Ideen umsetzten.





Mit Easy Table of Contents wird das Lesen von Artikel noch angenehmer! Ein Inhaltsverzeichnis (TOC) ist bereits ein nützliches Werkzeug, aber mit einigen Tipps und Modifikationen kannst du es noch effektiver nutzen. Entdecke, wie du Überschriften umbrichst, das Sticky TOC nur für Beiträge mit aktiviertem Hauptmenü anzeigen lässt und sogar einen Scroll-Hinweis für das Sticky TOC hinzufügst. Außerdem zeigen wir dir, wie du automatisch Anker für dein Inhaltsverzeichnis generierst. Tauche ein und optimiere deine Inhaltsstruktur für eine noch bessere Benutzererfahrung!

Um ein Inhaltsverzeichnis zu erstellen, gibt es verschiedene Plug-ins, die normalerweise kostenlos verfügbar sind. Eines der genannten ist das "Easy Table of Contents".

Die Installation und Verwendung ist in der Regel unkompliziert und erfordert keine besonderen technischen Kenntnisse. Typischerweise ist das Plug-in einfach herunterzuladen und zu aktivieren. Anschließend kann es automatisch oder manuell angepasst und in den Inhalt eingefügt werden.

Inhaltsverzeichnis mit Easy Table of Content

Easy Table of Content ist ein Plug-in für WordPress, das ähnlich wie "Table of Contents Plus" funktioniert. Es bietet jedoch ein anderes Design und zusätzliche Funktionen. Im Editor von WordPress ist eine Meta-Box verfügbar, die es ermöglicht, das Inhaltsverzeichnis individuell anzupassen. Diese Box kann über die Einstellungen → Ansicht anpassen → Table of Contents aktiviert werden.

Easy Table of Contents

… ein paar Tipps

  • Die individuellen Einstellungen können sehr nützlich sein, um das Inhaltsverzeichnis für bestimmte Beiträge auf der Website anzupassen. Zum Beispiel kann es für Beiträge, die ein "Tab-Menü" enthalten, von Vorteil sein, das Inhaltsverzeichnis nicht anzuzeigen.
  • Wenn man das Plug-in global einstellt, wird automatisch die Überschrift "Related Posts" dem Inhaltsverzeichnis hinzugefügt. Wenn man dies ausschließen möchte, kann man dies über die Einstellungen → Erweitert → "Ausschluss-IDs" tun und die ID der Überschrift "Related Posts" angeben.
  • Ein weiteres Beispiel für individuelle Einstellungen bei einem Inhaltsverzeichnis mit dem Plug-in "Easy Table of Contents" wäre, dass man die Überschriften von 2 bis 5 dem Inhaltsverzeichnis hinzufügen möchte, aber die Überschrift "Related Posts" ausschließen möchte:
    • Um dies zu erreichen, geht man zu den Einstellungen des Plug-ins und wählt unter "Erweitert" die Option "Überschriften". Dort kann man die gewünschten Überschriftennummern auswählen.
    • Unterhalb der Option "Überschriften ausschließen" ist hier bspw. den "Related Posts" die Überschrift auszuschließen. Siehe unterhalb des Beitrags: "👉🏿 Das könnte für Dich auch ansprechen" Diese Überschrift sollte Global ausgeblendet werden. Das funktioniert allein mit: 👉🏿 *

Auf diese Weise kann man das Inhaltsverzeichnis individuell anpassen und es auf die Bedürfnisse der eigenen Website zuschneiden.

Modifikationen für Easy Table of Content

Die Anpassungen haben sich während der Entwicklung der Website ergeben, wobei insbesondere dem Sticky TOC viel Aufmerksamkeit geschenkt wurde. Das Menü auf der linken Seite ist ein gutes Beispiel dafür, wie praktisch der Sticky TOC sein kann. Als nächstes wurden Tipps zum Zeilenumbruch von Überschriften im Haupt-Inhaltsverzeichnis sowie das Hinzufügen eines Ankers zum TOC entwickelt.

A) Sticky TOC Anpassungen – für ein Entspanntes Menüerlebnis!

Easy Table of Contents macht das Lesen von Artikeln noch angenehmer! Ein Inhaltsverzeichnis (TOC) ist bereits ein nützliches Werkzeug, aber mit Sticky TOC können Sie es noch effektiver nutzen.

  1. Sticky-Open-Icon nur für Beiträge anzeigen, in denen das Hauptmenü aktiviert ist
  2. Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses
  3. Sticky-Menü vertikal zentriert
  4. Hinzufügen eines Scroll-Hinweises zum Sticky-Menü
  5. Sticky-Menü mit Resizable Handles
  6. Sticky-Menü bleibt geöffnet
  7. Resizable Überschriften: Schnelle Navigation und Übersicht 🧡
  8. Link-Hinweis im Sticky-Menü
  9. Das CSS in einem

Bezüglich etwaiger Probleme bei den Anpassungen möchte ich auch darauf hinweisen, dass man generell auf mögliche variationsspezifische Aspekte von Themes vorbereitet sein sollte.

  • Die Empfehlung PRO ist ohne Workflows.

1. Sticky TOC Open-Icon nur bei aktiviertem Hauptmenü anzeigen

Beispielsweise wird das Inhaltsverzeichnis für jeden Beitrag separat definiert. Dies erfolgt unterhalb des Editors im Bereich "Inhaltsverzeichnis". In den Haupteinstellungen ist die Option "Unterstützung aktivieren" entsprechend aktiviert, jedoch ohne automatische Einfügung.

Das Problem, das durch die Standardfunktion nicht gelöst wurde, besteht darin, dass das Sticky-Button automatisch für alle Beiträge aktiviert ist. Eine mögliche Lösung wäre, die Beiträge, für die der Sticky-Button ausgeschlossen werden soll, manuell in den Sticky-Einstellungen unter "Ausschließen durch Übereinstimmung mit URL/String" anzugeben. Dies erfordert jedoch eine umständliche manuelle Zuordnung, insbesondere für Seiten mit vielen Beiträgen.

Daher haben wir dieses Problem mit einer Kombination aus JavaScript und CSS gelöst, um sicherzustellen, dass der Sticky-Button nur für Beiträge sichtbar ist, für die auch das Hauptmenü aktiviert wurde.

Zuerst wird der Sticky-Button standardmäßig ausgeblendet, indem er mit CSS ausgeblendet wird:

/* --- Sticky-Open-Icon mit CSS ausblenden und mit JS einblenden --- */

.ez-toc-sticky {
	display: none;
}

Dadurch bleibt der Sticky-Button trotz der Aktivierung in den Einstellungen für alle Beiträge ausgeblendet.

Flexible Inhaltsverzeichnisse – definiere sie nach Bedarf!

Das folgende JavaScript sorgt dafür, dass das Sticky-Element wieder angezeigt wird, wenn der Container mit der Classe ez-toc-container im Inhalt des Beitrags vorhanden ist. Andernfalls bleibt das Sticky-Element ausgeblendet:

/* --- Sticky-Open-Icon einblenden vs. CSS ausblenden --- */

document.addEventListener("DOMContentLoaded", function() {
    // Überprüfe, ob der Container mit der Klasse "ez-toc-container" vorhanden ist
    var tocContainer = document.getElementById('ez-toc-container');
    if (tocContainer) {
        // Zeige das Sticky-Element an
        var stickyElement = document.querySelector('.ez-toc-sticky');
        if (stickyElement) {
            stickyElement.style.display = 'block';
        }
    }
});

/* Ende Sticky-Open-Icon einblenden vs. CSS ausblenden */

Im vorliegenden Code wird das Sticky-Element je nach dem Vorhandensein eines Containers mit der Classe ez-toc-container entweder ein- oder ausgeblendet. Dies geschieht durch Hinzufügen oder Entfernen der CSS-Eigenschaft display: block des Sticky-Elements mit der Classe ez-toc-sticky.

Die document.addEventListener("DOMContentLoaded", function() wird verwendet, um sicherzustellen, dass der Code erst ausgeführt wird, wenn der DOM-Inhalt vollständig geladen ist. Dies ermöglicht es, auf DOM-Elemente zuzugreifen, sobald sie verfügbar sind, was besonders wichtig ist, wenn Änderungen am DOM vorgenommen werden sollen.

Warum wird hier jedoch nicht der window.addEventListener('load', function() verwendet? Der Unterschied liegt in dem Zeitpunkt, zu dem diese Events ausgelöst werden. Das Event DOMContentLoaded wird ausgelöst, sobald der HTML-Parser den gesamten DOM-Baum erstellt hat, während das window.load-Event ausgelöst wird, sobald alle Ressourcen einer Webseite geladen wurden, einschließlich Bilder, Stylesheets und Skripte. Das DOMContentLoaded-Event tritt also früher auf als das window.load-Event.

In diesem Fall, in dem das Sticky-Element basierend auf dem DOM-Inhalt manipuliert wird, genügt das DOMContentLoaded-Event, da die Manipulation des Sticky-Elements nicht von Ressourcen abhängt, die möglicherweise noch nicht vollständig geladen sind. Das window.load-Event könnte hier unnötige Verzögerungen verursachen, da der Code erst ausgeführt würde, nachdem alle Ressourcen geladen sind, was nicht erforderlich ist.

Deshalb wird das DOMContentLoaded-Event bevorzugt, um sicherzustellen, dass der Code so früh wie möglich ausgeführt werden kann, was zu einer verbesserten Benutzererfahrung führt.

2. Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses

Beim Besuch der Webseite sollte das Sticky-Menü standardmäßig sichtbar sein. Diese Einstellung kann in den Hauptoptionen unter "TOC open on load" aktiviert werden. Dadurch wird das Sticky-Menü direkt beim Laden der Webseite geöffnet und legt sich über das Headerbild und andere Elemente.

Allerdings haben wir eine alternative Lösung implementiert: Das Menü öffnet sich erst, wenn der Benutzer zum Haupt-Inhaltsverzeichnis scrollt – was in den meisten Fällen ideal ist und ein schöneres Benutzererlebnis bietet. Dies erfordert zusätzliches JavaScript:

/* --- Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses --- */

function ezTOC_showBar() {
    var sidebar = document.querySelector(".ez-toc-sticky-fixed");
    if (sidebar) {
        sidebar.classList.remove("hide");
        sidebar.classList.add("show");
    }
}

function ezTOC_hideBar() {
    var sidebar = document.querySelector(".ez-toc-sticky-fixed");
    if (sidebar) {
        sidebar.classList.remove("show");
        sidebar.classList.add("hide");
        document.querySelector(".ez-toc-open-icon").style.zIndex = "9999999";
    }
}

window.addEventListener('scroll', function() {
    var container = document.getElementById('ez-toc-container');
    var sidebar = document.querySelector(".ez-toc-sticky-fixed");

    if (container && sidebar) {
        var containerRect = container.getBoundingClientRect();
        var containerTop = containerRect.top;

        // Einblenden des Sticky-Menüs, wenn der Container oben im Viewport angekommen ist
        if (containerTop <= 0) {
            ezTOC_showBar();
            sidebar.style.zIndex = "999"; // Setze den Z-Index-Wert des Sticky-Menüs
            document.querySelector(".ez-toc-open-icon").style.zIndex = "-1";
            // Entferne den Event Listener, um das automatische Einblenden zu stoppen
            window.removeEventListener('scroll', arguments.callee);
        } else {
            ezTOC_hideBar();
        }
    }
});

/* Ende Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses */

Nachdem das Menü erfolgreich eingeblendet wurde, wird der 'Event Listener' entfernt. Dadurch wird das Sticky-Menü automatisch nur einmalig eingeblendet und danach nicht mehr, wenn es durch einen Klick in die Seite oder durch den Schließen-Button geschlossen wurde. Das Sticky-Menü kann erneut geöffnet werden, indem der Sticky-Button angeklickt wird.

Das Ausklappen des Sticky-Menüs kann durch zusätzliches CSS weiter verbessert werden. Dabei wird das Sticky-Menü konsistent und ansprechend wieder eingeklappt, ohne die Notwendigkeit von separatem CSS für das Einklappen.

/* --- Sticky-Menü langsam Einblenden CSS --- */

.ez-toc-sticky-fixed {
    opacity: 0;
    transition: width 1s ease, opacity 2s ease;
}

.ez-toc-sticky-fixed.show {   
    opacity: 1;
}

/* CSS-Animation für das Einblenden des Menüs */
@keyframes rollInFromLeft {
    from {
        transform: translateX(-100%);
    }
    to {
        transform: translateX(0);
    }
}

.ez-toc-sticky-fixed.show {
    animation: rollInFromLeft 1.3s ease forwards;
}

/* Ende Sticky TOC Menü langsam Einblenden */

Sticky-Menü – Konformes Ein- und Ausklappen.

3. Zentrieren des Sticky TOC Menüs vertikal

toc-sticky-desktop-links-mitte
Sticky TOC der Haupteinstellungen.

Wenn man der Haupteinstellung den Sticky-Button der Ausrichtung Mitte hat, dann sollte möglicherweise auch das Inhaltsverzeichnis zentriert sein.

Dies scheint zunächst recht einfach zu sein:

/* So nicht anzuwenden */
.ez-toc-sidebar {
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
}

Jedoch kam es dabei zu einem Konflikt mit anderen CSS-Regeln oder aufgrund einer unerwarteten Struktur. Daher sollte dies alleinig(!) per JavaScript erfolgen:

/* --- Sticky-Menü vertikal zentriert --- */

function centerSidebarVertically() {
    var sidebar = document.querySelector('.ez-toc-sidebar');

    if (sidebar) {
        var windowHeight = window.innerHeight; // Höhe des sichtbaren Bereichs des Bildschirms
        var sidebarHeight = sidebar.offsetHeight; // Höhe der Seitenleiste

        // Berechne die obere Position der Seitenleiste, um sie vertikal zentriert zu halten
        var topPosition = (windowHeight - sidebarHeight) / 2;

        // Setze die obere Position der Seitenleiste
        sidebar.style.top = topPosition + 'px';
    }
}

// Füge einen Event-Listener hinzu, um die Seitenleiste neu zu positionieren, wenn sich die Fenstergröße ändert
window.addEventListener('resize', centerSidebarVertically);

// Rufe die Funktion auf, um die Seitenleiste initial vertikal zentriert zu positionieren
window.onload = centerSidebarVertically;

/* Ende Sticky-Menü vertikal zentriert */

In diesem Skript wird die centerSidebarVertically Funktion direkt nach ihrer Definition aufgerufen. Dadurch wird sichergestellt, dass die Seitenleiste sofort nach dem Laden der Seite vertikal zentriert wird.

4. Scroll-Hinweis zum Sticky TOC Menü

Der Scrollbalken im Sticky-Inhaltsverzeichnis erscheint nur dann, wenn tatsächlich gescrollt wird. Daher sollte angezeigt werden, dass das Sticky-Menü gescrollt werden kann. Wenn der Inhalt länger ist als der definierte Abschnitt (zum Beispiel 600px), sollte ein visueller Hinweis angezeigt werden, ansonsten nicht.

Mit JavaScript und CSS machen wir den Hinweis. Hier ist das entsprechende CSS:

/* --- Sticky Hinweis zum Scrollen CSS --- */

.ez-toc-sticky-title::after {
    opacity: 0;
}

.ez-toc-sticky-title.visible::after {
    content: "Scrollen";
    position: absolute;
    left: 50%;
    background-color: rgba(0, 0, 0, 0.5);
    color: #ffffff;
    padding: 5px 10px;
    border-radius: 5px;
    font-size: 14px;
    transition: opacity 0.3s ease-out;
    opacity: 1;
}

.ez-toc-sticky-title-container {
	position: sticky !important;
	margin-left: -15px;
	float: left;
}

.ez-toc-sidebar {
	padding-top: 0px !important;
}

.ez-toc-sticky-fixed .ez-toc-close-icon {
	margin: 2px 0 0 0;
	font-size: 1.5rem;
	color: #4F5279;
}

/* Ende Sticky Hinweis zum Scrollen CSS */

Die Attributwerte sind natürlich individueller Natur!

… und JavaScript:

/* --- Sticky Hinweis zum Scrollen --- */

window.addEventListener('load', function() {
    var stickyTitle = document.querySelector('.ez-toc-sticky-title');
    var stickyContainer = document.querySelector('.ez-toc-sticky-container');

    // Überprüfen, ob sowohl der Sticky-Titel als auch der Sticky-Container existieren
    if (stickyTitle && stickyContainer) {
        // Überprüfen, ob der Inhalt des Sticky-Bereichs über 550px liegt
        if (stickyContainer.offsetHeight > 550) {
            stickyTitle.classList.add('visible');
        } else {
            stickyTitle.classList.remove('visible');
        }
    }
});

/* Ende Sticky Hinweis zum Scrollen */

In diesem Beispiel verwenden wir window.addEventListener('load', function() anstelle von document.addEventListener("DOMContentLoaded", function(), um sicherzustellen, dass der Code erst ausgeführt wird, nachdem alle Ressourcen der Seite vollständig geladen wurden. Warum ist das wichtig? Nun, window.onload  wird normalerweise verwendet, um sicherzustellen, dass der Code ausgeführt wird, sobald der DOM-Baum vollständig analysiert und erstellt wurde. Es wird jedoch festgestellt, dass einige Inhalte, wie z. B. Bilder und externe Skripte, möglicherweise noch nicht geladen wurden, wenn DOMContentLoaded ausgelöst wird. Dies könnte dazu führen, dass der Code vorzeitig ausgeführt wird und auf nicht vollständig geladene Inhalte zugreift, was zu unerwartetem Verhalten führen kann.

Durch die Verwendung von window.onload stellen wir sicher, dass der Code erst ausgeführt wird, nachdem alle Inhalte auf der Seite, einschließlich Bilder, Skripte und andere Ressourcen, vollständig geladen wurden. Dadurch wird vermieden, dass der Code vorzeitig ausgeführt wird und auf nicht vollständig geladene Inhalte zugreift.

In diesem speziellen Beispiel überprüfen wir die Höhe des Sticky-Bereichs und entscheiden dann, ob der Scroll-Hinweis angezeigt werden soll. Indem wir sicherstellen, dass der Code erst nach dem Laden der gesamten Seite ausgeführt wird, können wir sicher sein, dass alle Inhalte korrekt geladen und bereit sind, und somit wird der Scroll-Hinweis nur angezeigt, wenn man ihn wirklich braucht.

5. Handles zum Sticky-Menü

Die Implementierung eines Griffs ermöglicht es den Benutzern, die Größe und Form des Sticky-Menüs nach ihren Bedürfnissen anzupassen.

Diese Flexibilität verbessert die Benutzererfahrung, da das Menü an verschiedene Bildschirmgrößen angepasst werden kann. Zudem erhöht sich die Schriftgröße auf 16 Pixel, wenn das Menü erweitert wird. Bei einer Verkleinerung des Menüs wird die Schriftgröße auf den ursprünglichen Wert zurückgesetzt.

Anzumerken ist, dass wir die Einstellungen des Sticky-Menüs auf eine individuelle Breite von 350 Pixel eingestellt haben. Dies ist die grundlegende Einstellung. Mit dem folgenden JavaScript kann das Menü auf 300 Pixel verschmälert und auf 500 Pixel erweitert werden.

/* --- Sticky-Menü mit Resizable Handles --- */

(function() {
    // Funktion zum Initialisieren des Resizable Handles
    function initResizable(element) {
        if (!element) return; // Überprüfen, ob das Element vorhanden ist

        var startX, startY, startWidth, startHeight;

        var resizeHandle = document.createElement('div');
        resizeHandle.className = 'ez-toc-resize-handle';
        resizeHandle.style.position = 'fixed';
        resizeHandle.style.bottom = '0';
        resizeHandle.style.right = '0';
        resizeHandle.style.width = '20px';
        resizeHandle.style.height = '20px';
        resizeHandle.style.background = '#ddd';
        resizeHandle.style.cursor = 'nwse-resize';
        resizeHandle.classList.add('resize-handle-icon');

        element.appendChild(resizeHandle);

        function startResize(e) {
            e.preventDefault();
            startX = e.clientX;
            startY = e.clientY;
            startWidth = element.getBoundingClientRect().width;
            startHeight = element.getBoundingClientRect().height;
            document.addEventListener('mousemove', doResize);
            document.addEventListener('mouseup', stopResize);
        }

        function doResize(e) {
            var newWidth = startWidth + (e.clientX - startX);
            var newHeight = startHeight + (e.clientY - startY);
            newWidth = Math.max(newWidth, 300);
            newHeight = Math.max(newHeight, 600);
            newWidth = Math.min(newWidth, 500);
            element.style.width = newWidth + 'px';
            element.style.height = newHeight + 'px';

            adjustFontSize(newWidth); // Schriftgröße anpassen
        }

        function stopResize() {
            document.removeEventListener('mousemove', doResize);
            document.removeEventListener('mouseup', stopResize);
        }

        resizeHandle.addEventListener('mousedown', startResize);
    }

    function adjustFontSize(width) {
        var links = document.querySelectorAll('.ez-toc-sticky-list');
        if (width >= 400) { // Bedingung, um die Schriftgröße anzupassen
            links.forEach(function(link) {
                link.style.fontSize = '16px';
            });
        } else {
            links.forEach(function(link) {
                link.style.fontSize = ''; // Rücksetzen auf Standardwert
            });
        }
    }

    var sidebar = document.querySelector('.ez-toc-sidebar');
    initResizable(sidebar);

    // Event-Listener zum Überwachen der Größe des Browserfensters hinzufügen
    window.addEventListener('resize', function() {
        if (sidebar) {
            var width = sidebar.getBoundingClientRect().width;
            adjustFontSize(width); // Schriftgröße beim Ändern der Fenstergröße anpassen
        }
    });
})();

/* Ende Sticky-Menü mit Resizable Handles */

Anmerkung zur Positionierung des Griffs: Aufgrund der vertikalen Zentrierung des Sticky-Menüs kann der Griff nicht in der rechten unteren Ecke platziert werden. Andere Ansätze waren erfolglos, daher muss man sich damit arrangieren, wenn man die vertikale Zentrierung des Menüs bevorzugt.

6. Sticky-Menü bleibt geöffnet

Das Sticky-Menü wird nach anklicke in die Seite automatisch geschlossen. Das Sticky-Menü geöffnet zu lassen ist zwar möglich, indem man "Click TOC Close on desktop" nicht anhakt jedoch nicht funktional in dieser Einstellung.

Um diese Funktion zu implementieren, ist es erforderlich, Änderungen direkt in die Datei (ez-toc-sticky.min.js) des Plug-ins vorzunehmen.

Plugin-Dateien > assets > js > ez-toc-sticky.min.js

  • Das vorhandene JS auskommentieren genügt zur Zeit Version 2.0.68.1 (Juli 2024) und sollte nach erneuten Update überprüft werden.

Es war davor, sodass dies mit folgendem Code zu ersetzen war. Beachte, dass dieser Code nach einem Update des Plug-ins möglicherweise erneut eingefügt werden muss.

/* --- Sticky-Menü bleibt geöffnet (ez-toc-sticky.min.js) --- */

(function() {
    function ezTOC_hideBar(e) {
        var sidebar = document.querySelector(".ez-toc-sticky-fixed");
        if (typeof(sidebar) !== "undefined" && sidebar !== null) {
            if (e.target.classList.contains('ez-toc-close-icon') || e.target.parentElement.classList.contains('ez-toc-close-icon')) {
                sidebar.classList.remove("show");
                sidebar.classList.add("hide");
            }
        }
    }

    function ezTOC_showBar() {
        var sidebar = document.querySelector(".ez-toc-sticky-fixed");
        if (sidebar.classList.contains("hide")) {
            sidebar.classList.remove("hide");
            sidebar.classList.add("show");
            // Stelle sicher, dass der Schließen-Button korrekt dargestellt wird
            document.querySelector(".ez-toc-close-icon").style.zIndex = "9999999";
        }
    }

    let ez_toc_sticky_fixed_container = document.querySelector('div.ez-toc-sticky-fixed');
    if (ez_toc_sticky_fixed_container) {
        document.body.addEventListener("click", function(evt) {
            // Überprüfen, ob das Menü sichtbar ist
            var sidebar = document.querySelector(".ez-toc-sticky-fixed");
            if (sidebar.classList.contains("show")) {
                // Menü nur schließen, wenn der Schließen-Button nicht geklickt wurde
                if (!evt.target.classList.contains('ez-toc-close-icon') && !evt.target.parentElement.classList.contains('ez-toc-close-icon')) {
                    ezTOC_hideBar(evt);
                }
            }
        });

        document.querySelector('.ez-toc-close-icon').addEventListener('click', function(event) {
            ezTOC_hideBar(event);
            event.stopPropagation();
        });
        ez_toc_sticky_fixed_container.addEventListener('click', function(event) {
            event.stopPropagation();
        });
        document.querySelector('.ez-toc-open-icon').addEventListener('click', function(event) {
            ezTOC_showBar();
            event.stopPropagation();
        });
    }

    if(1 === parseInt(eztoc_sticky_local.close_on_link_click)){
        jQuery(document).ready(function() {
            jQuery("#ez-toc-sticky-container a.ez-toc-link").click(function(e) {
                ezTOC_hideBar(e);
            });
        });
    }
})();

/* Ende Sticky-Menü bleibt geöffnet */

Bereit für Anpassungen?
Sei auf unterschiedliche Aspekte vorbereitet!

7. Resizable Überschriften im Sticky TOC 🧡

Resizable Überschriften, das ist der Kern von Sticky-TOC: Schnelle Navigation und Übersicht im Sticky TOC. Resizable bedeutet anpassbar, veränderbar und wird auch im Kontext der Hervorhebung oder Markierung von aktuellen Überschriften verwendet.

  • Die Empfehlung PRO erfordert keine Workflows.

Das Sticky-Menü, das beim Scrollen an Ort und Stelle bleibt, ist eine gängige Praxis, um die Navigation auf einer Website zu verbessern. Die Idee von Resizable Überschriften, die sich an die Scrollposition anpassen und möglicherweise markieren, sind eine weitere Designinnovation, die die Lesbarkeit verbessern kann.

Die Einführung von resizable Überschriften in Verbindung mit Sticky-Menüs erfolgte wahrscheinlich in den Jahren, als responsives Webdesign und die Benutzererfahrung (UX) im Webdesign immer besser wurden. Dies könnte irgendwann zwischen Mitte und Ende der 2010er Jahre gewesen sein. Diesem Design möchte hier ein Dankeschön bekundet sein!

Die Sticky TOC-Navigation ermöglicht es, die Übersicht immer im Blick zu behalten und bietet eine effiziente Navigation durch den Artikel. Besonders leistungsfähig wird diese Funktion in Verbindung mit resizablen Überschriften. Dadurch ist es sofort ersichtlich, in welchem Abschnitt des Artikels man sich befindet, sobald die entsprechende Überschrift markiert ist.

  • Beachte: Das folgende CSS und die Programmierungen erfolgten in Entwicklung. Der wirklich relevante Code befindet sich im Abschnitt 'Erfolg: Browser Firefox, Chrome, Edge, Opera, Safari'. Dennoch enthält dieser Abschnitt weiterhin wichtige Informationen.

CSS (Entwicklung)

/* CSS Sticky TOC Resizable Überschriften */
.ez-toc-sidebar a.active {
    font-weight: 500;
    background-color: #7f7f7f;
    color: #fff !important;
    padding: 0px 5px;
    border-radius: 4px;
}

.ez-toc-sidebar a:focus {
    outline: none;
}

/* Verstecken der Scrollleisten in Webkit-basierten Browsern (Chrome, Safari) */
.ez-toc-sidebar::-webkit-scrollbar {
    display: none;
}

/* Verstecken der Scrollleisten in Firefox */
@-moz-document url-prefix() {
    .ez-toc-sidebar {
        scrollbar-width: none;
    }
}

/* Ende Sticky-Menü Resizable Überschriften */
  • .ez-toc-sidebar a.active markiert die aktive Überschrift und kann individuell angepasst werden.
  • Mit .ez-toc-sidebar a:focus verhindern wir potenzielle Artefakte. Nachdem im Sticky-Menü eine Überschrift angeklickt und anschließend im Inhalt gescrollt wurde, kann ein Artefakt im Sticky-Menü der angeklickten Überschrift zurückbleiben. Dieses Artefakt wurde durch das CSS entfernt.
  • Schließlich wird mit .ez-toc-sidebar::-webkit-scrollbar die Scrollleiste ausgeblendet. Die Scrollleiste im Sticky-Menü wird durch das automatische Scrollen überflüssig daher kann das ausgeblendet werden, was zu einem noch entspannteren Menüerlebnis führt. Dasselbe für @-moz-document url-prefix().

Die JavaScript-Funktion zum Hervorheben der aktuellen Überschrift im Menü basiert auf der Scrollposition.

Für Firefox konnten wir das automatische Scrollen und das Resizable mit folgendem JS nicht problemlos umsetzen. Firefox hat einige Eigenheiten, die dazu führen können, dass bestimmte Funktionen anders oder gar nicht funktionieren, insbesondere wenn es um das Scrollen und das Handling von Scroll-Positionen geht. Folgendem Code ist Firefox exclude der Resizable Überschriften. Es wäre sicherlich möglich diese beiden Codes zu vereingischen, aber zur Wartbarkeit hat es einen großen Vorteil diese getrennt zu behandeln. Daher folgt für Firefox ein separater Code.

Der separate Code für Firefox funktioniert auch für die anderen Browser und unterscheidet sich nur durch Nuancen in normalerweise nicht erkennbarer Funktionalität. (Es kann vorkommen, dass sich die Markierung nicht auf die oberste Überschrift setzt, wenn man einen Button zum Zurück-zum-Inhaltsverzeichnis verwendet.) Wem das vernachlässigbar erscheint, für den funktioniert der eine Code für alle Browser, den ich im Anschluss an den Firefox-spezifischen Code bereitgestellt habe.

Browser Chrome, Edge, Opera und Safari (Entwicklung)
/* --- Sticky-Menü Resizable Überschriften, Firefox excluded --- */

(function() {
    var isFirefox = typeof InstallTrigger !== 'undefined';

    if (isFirefox) {
        // Beenden der Funktion, wenn der Browser Firefox ist
        return;
    }

    var lastScrollTop = 0;
    var previousActiveHeading = null;

    function updateHeadingHighlight() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        var windowHeight = window.innerHeight;
        var scrollTop = window.scrollY;
        var sidebar = document.querySelector('.ez-toc-sidebar');

        // Finde die Überschrift, die sich am nächsten am mittleren Rand des Bildschirms befindet
        var closestHeading = null;
        var closestDistance = Infinity;
        headings.forEach(function(heading) {
            var targetId = heading.getAttribute('href').substring(1);
            var targetHeading = document.getElementById(targetId);
            if (targetHeading) {
                var headingRect = targetHeading.getBoundingClientRect();
                var middleOfViewport = windowHeight / 6; // Mitte des Viewports
                var distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport); // Distanz zwischen Mitte der Überschrift und Mitte des Viewports
                var threshold = windowHeight / 4; // Schwelle für die Markierung 4 = weiter oben, 2 = mittig 
                if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
                    closestDistance = distanceToMiddle;
                    closestHeading = heading;
                }
            }
        });

        // Markiere die gefundene Überschrift und entferne Markierung von anderen Überschriften
        if (closestHeading) {
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            closestHeading.classList.add('active');

            // Überprüfen, ob das Menü scrollbar ist und sich der Scroller nach unten bewegen muss
            if (sidebar.scrollHeight > sidebar.clientHeight) {
                // Berechnen der Position, um die die markierte Überschrift mittig im sichtbaren Bereich zu halten
                var targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 4 - closestHeading.offsetHeight / 2);
                sidebar.scrollTop = targetPosition;
            }

            // Speichern der aktuellen aktiven Überschrift
            previousActiveHeading = closestHeading;
        }

        // Speichern des aktuellen Scrollwerts für den nächsten Durchlauf
        lastScrollTop = scrollTop;
    }

    document.addEventListener('scroll', updateHeadingHighlight);
    document.addEventListener('DOMContentLoaded', updateHeadingHighlight);

    // Event-Listener für das Anklicken eines Menülinks
    document.addEventListener('DOMContentLoaded', function() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        headings.forEach(function(heading) {
            heading.addEventListener('click', function(event) {
                // Entferne die aktive Markierung von allen Überschriften im Menü, außer dem Schließenkreuz
                if (!this.classList.contains('ez-toc-close-icon')) {
                    headings.forEach(function(heading) {
                        heading.classList.remove('active');
                    });

                    // Füge die aktive Markierung zur angeklickten Überschrift hinzu
                    this.classList.add('active');

                    // Verhindere den Standardverhalten des Links (z. B. das Scrollen zur Ankerposition)
                    event.preventDefault();
                }
            });
        });
    });

    // Event-Listener für das Klicken auf das Schließenkreuz
    var closeIcon = document.querySelector('.ez-toc-close-icon');
    if (closeIcon) {
        closeIcon.addEventListener('click', function() {
            // Entferne die aktive Markierung von allen Überschriften im Menü
            var headings = document.querySelectorAll('.ez-toc-sidebar a');
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            // Wiederherstellen der vorherigen aktiven Überschrift, falls vorhanden
            if (previousActiveHeading) {
                previousActiveHeading.classList.add('active');
            }
        });
    }
})();

/* Ende Sticky-Menü Resizable Überschriften, Firefox excluded */

Überprüfe den Schwellenwert für die Markierung im Menü, das heißt, ab welchem Scrollpunkt im Inhalt die nächste Markierung erfolgen soll:

var threshold = windowHeight / 4; // Schwelle für die Markierung 4 = weiter oben, 2 = mittig

Prüfe den ersten Wert bei windowHeight, ab wann der Scroll aktiv sein sollte, d.h. ob ab Mitte (4) wie vorgegeben oder eher am Ende mit (2) statt (4):

var targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 4 - closestHeading.offsetHeight / 2);

Highlighten im Sticky TOC betonen die Flexibilität der Navigation

Browser Firefox (Entwicklung)

Der Initialzündung ist das funktionell. Ein Problem trat immer auf, wenn das Menü länger wurde und das Scrollbare wirksam wurde. Somit waren einige Anpassungen erforderlich, wobei ein kleiner Haken verblieb: die Überschriften im Menü bleiben beim Zurück scrollen nach oben manchmal nicht am oberen Rand haften.

/* - Sticky-Menü Resizable Überschriften; Firefox - */

(function() {
    var lastScrollTop = 0;
    var previousActiveHeading = null;

    // Prüfen, ob der Browser Firefox ist
    var isFirefox = typeof InstallTrigger !== 'undefined';

    function updateHeadingHighlight() {
        if (!isFirefox) return; // Beenden, wenn der Browser nicht Firefox ist

        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        var windowHeight = window.innerHeight;
        var scrollTop = window.scrollY;
        var sidebar = document.querySelector('.ez-toc-sidebar');

        // Finde die Überschrift, die sich am nächsten am mittleren Rand des Bildschirms befindet
        var closestHeading = null;
        var closestDistance = Infinity;
        headings.forEach(function(heading) {
            var targetId = heading.getAttribute('href').substring(1);
            var targetHeading = document.getElementById(targetId);
            if (targetHeading) {
                var headingRect = targetHeading.getBoundingClientRect();
                var middleOfViewport = windowHeight / 2; // Mitte des Viewports
                var distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport); // Distanz zwischen Mitte der Überschrift und Mitte des Viewports
                if (distanceToMiddle < closestDistance && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
                    closestDistance = distanceToMiddle;
                    closestHeading = heading;
                }
            }
        });

        // Markiere die gefundene Überschrift und entferne Markierung von anderen Überschriften
        if (closestHeading) {
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            closestHeading.classList.add('active');

            // Scroll-Positionierung für Firefox
            if (sidebar.scrollHeight > sidebar.clientHeight) {
                var sidebarTop = sidebar.getBoundingClientRect().top;
                var headingTop = closestHeading.getBoundingClientRect().top;
                var scrollOffset = headingTop - sidebarTop - (windowHeight / 2 - closestHeading.offsetHeight / 2);
                
                // Sicherstellen, dass das Scrollen innerhalb der Grenzen des Sidebars bleibt
                sidebar.scrollTop += scrollOffset;
            }

            // Speichern der aktuellen aktiven Überschrift
            previousActiveHeading = closestHeading;
        }

        // Speichern des aktuellen Scrollwerts für den nächsten Durchlauf
        lastScrollTop = scrollTop;
    }

    document.addEventListener('scroll', throttle(updateHeadingHighlight, 100));
    document.addEventListener('DOMContentLoaded', updateHeadingHighlight);

    // Event-Listener für das Anklicken eines Menülinks
    document.addEventListener('DOMContentLoaded', function() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        headings.forEach(function(heading) {
            heading.addEventListener('click', function(event) {
                // Entferne die aktive Markierung von allen Überschriften im Menü, außer dem Schließenkreuz
                if (!this.classList.contains('ez-toc-close-icon')) {
                    headings.forEach(function(heading) {
                        heading.classList.remove('active');
                    });

                    // Füge die aktive Markierung zur angeklickten Überschrift hinzu
                    this.classList.add('active');
                    // Verhindere den Standardverhalten des Links (z. B. das Scrollen zur Ankerposition)
                    event.preventDefault();
                    document.getElementById(this.getAttribute('href').substring(1)).scrollIntoView({ behavior: 'smooth' });

                    // Scroll-Positionierung für Firefox
                    if (isFirefox) {
                        var sidebar = document.querySelector('.ez-toc-sidebar');
                        var sidebarTop = sidebar.getBoundingClientRect().top;
                        var headingTop = heading.getBoundingClientRect().top;
                        var scrollOffset = headingTop - sidebarTop - (window.innerHeight / 2 - heading.offsetHeight / 2);
                        
                        // Sicherstellen, dass das Scrollen innerhalb der Grenzen des Sidebars bleibt
                        sidebar.scrollTop += scrollOffset;
                    }
                }
            });
        });
    });

    // Event-Listener für das Klicken auf das Schließenkreuz
    var closeIcon = document.querySelector('.ez-toc-close-icon');
    if (closeIcon) {
        closeIcon.addEventListener('click', function() {
            // Entferne die aktive Markierung von allen Überschriften im Menü
            var headings = document.querySelectorAll('.ez-toc-sidebar a');
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            // Wiederherstellen der vorherigen aktiven Überschrift, falls vorhanden
            if (previousActiveHeading) {
                previousActiveHeading.classList.add('active');
            }
        });
    }

    // Throttle-Funktion zur Begrenzung der Aufrufhäufigkeit
    function throttle(func, limit) {
        var lastFunc;
        var lastRan;
        return function() {
            var context = this;
            var args = arguments;
            if (!lastRan) {
                func.apply(context, args);
                lastRan = Date.now();
            } else {
                clearTimeout(lastFunc);
                lastFunc = setTimeout(function() {
                    if ((Date.now() - lastRan) >= limit) {
                        func.apply(context, args);
                        lastRan = Date.now();
                    }
                }, limit - (Date.now() - lastRan));
            }
        }
    }
})();

/* Ende Sticky-Menü Resizable Überschriften; Firefox */
Erfolg: Browser Chrome, Firefox, Edge, Safari, Opera

Dieser Code für alle gängigen Browser, wie oben beschrieben, modernisiert und optimiert.

  • Beachte: Das CSS, das hierfür teilweise neu geschrieben werden muss, befindet sich im Abschnitt '9. CSS in einem Bündel'.

Es ist erwünscht, gern mit Audio! – zum Dank der Erfindung der 'Resizable Überschriften' und zur Präsentation des JS.

"Der Herr hat gewonnen" (The Lord has won), bereitgestellt von Oleksii_Kalyna.

/* --- Sticky-Menü Resizable Überschriften; Browser allgemein --- */

(() => {
	let lastScrollTop = 0;
	let previousActiveHeading = null;

	const updateHeadingHighlight = () => {
		const headings = document.querySelectorAll('.ez-toc-sidebar a');
		const windowHeight = window.innerHeight;
		const scrollTop = window.scrollY;
		const sidebar = document.querySelector('.ez-toc-sidebar');
		const stickyContainer = document.querySelector('.ez-toc-sticky-title-container');
		const stickyTitle = stickyContainer ? stickyContainer.querySelector('.ez-toc-sticky-title') : null;

		let closestHeading = null;
		let closestDistance = Infinity;

		// Bestimme die am nächsten zur Mitte des Bildschirms liegende Überschrift
		const updateActiveHeading = () => {
			let closestHeading = null;
			let closestDistance = Infinity;
			const windowHeight = window.innerHeight;

			headings.forEach(heading => {
				const targetId = heading.getAttribute('href').substring(1);
				const targetHeading = document.getElementById(targetId);
				if (targetHeading) {
					const headingRect = targetHeading.getBoundingClientRect();
					const middleOfViewport = windowHeight / 6; // Höhe von einem Sechstel des Viewports
					const distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport); // Distanz zwischen Mitte der Überschrift und dem mittleren Drittel des Viewports
					const threshold = windowHeight / 4; // Schwelle für die Markierung (4 = weiter oben, 2 = mittig)

					if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
						closestDistance = distanceToMiddle;
						closestHeading = heading;
					}
				}
			});

			// Markiere die gefundene Überschrift und entferne die Markierung von anderen Überschriften
			if (closestHeading) {
				headings.forEach(heading => heading.classList.remove('active'));
				closestHeading.classList.add('active');

				// Überprüfen, ob das Menü scrollbar ist und sich der Scroller nach unten bewegen muss
				if (sidebar.scrollHeight > sidebar.clientHeight) {
					// Berechnen der Position, um die markierte Überschrift mittig im sichtbaren Bereich zu halten
					const targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 4 - closestHeading.offsetHeight / 2);
					sidebar.scrollTop = targetPosition;
				}

				// Speichern der aktuellen aktiven Überschrift
				previousActiveHeading = closestHeading;
			}

			// Speichern des aktuellen Scrollwerts für den nächsten Durchlauf
			lastScrollTop = window.scrollY;
		};

		// Event Listener für das Scrollen hinzufügen
		window.addEventListener('scroll', updateActiveHeading);


		// Sticky-Handling für den Container
		if (stickyContainer && previousActiveHeading) {
			const stickyRect = stickyContainer.getBoundingClientRect();
			const activeHeadingRect = previousActiveHeading.getBoundingClientRect();

			// Zeige den Sticky Container an, wenn der aktive Heading im sichtbaren Bereich des Containers ist
			if (activeHeadingRect.top < windowHeight && activeHeadingRect.bottom > 0) {
				// Setze den Titel des Sticky Containers
				if (stickyTitle) {
					stickyTitle.textContent = "Inhaltsverzeichnis";
				}
				stickyContainer.style.position = 'fixed';
				stickyContainer.style.top = '0';
				stickyContainer.style.left = '0';
				stickyContainer.style.width = '100%';
				stickyContainer.style.zIndex = '1000';
				stickyContainer.style.backgroundColor = 'white'; // Ändere Hintergrundfarbe, wenn nötig
				stickyContainer.style.display = 'block'; // Stelle sicher, dass der Container sichtbar ist
				/*stickyContainer.style.height = 'auto';*/ // Dynamische Höhe
				stickyContainer.style.padding = '10px'; // Anpassbare Padding
				/*stickyContainer.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';*/ // Optionaler Schatten für bessere Sichtbarkeit
			} else {
				stickyContainer.style.display = 'none'; // Verstecke den Container, wenn er nicht benötigt wird
			}
		}

		lastScrollTop = scrollTop;
	};

	// Throttle-Funktion zum Begrenzen der Scroll-Event-Handler-Ausführungen
	const throttle = (func, limit) => {
		let lastFunc;
		let lastRan;
		return (...args) => {
			const context = this;
			if (!lastRan) {
				func.apply(context, args);
				lastRan = Date.now();
			} else {
				clearTimeout(lastFunc);
				lastFunc = setTimeout(() => {
					if ((Date.now() - lastRan) >= limit) {
						func.apply(context, args);
						lastRan = Date.now();
					}
				}, limit - (Date.now() - lastRan));
			}
		};
	};

	// Event-Listener für Scroll- und DOMContentLoaded-Ereignisse
	document.addEventListener('scroll', throttle(updateHeadingHighlight, 100));
	document.addEventListener('DOMContentLoaded', updateHeadingHighlight);

	document.addEventListener('DOMContentLoaded', () => {
		const headings = document.querySelectorAll('.ez-toc-sidebar a');
		headings.forEach(heading => {
			heading.addEventListener('click', (event) => {
				if (!heading.classList.contains('ez-toc-close-icon')) {
					headings.forEach(h => h.classList.remove('active'));
					heading.classList.add('active');
					event.preventDefault();
					document.getElementById(heading.getAttribute('href').substring(1)).scrollIntoView({
						behavior: 'smooth'
					});

					const sidebar = document.querySelector('.ez-toc-sidebar');
					const sidebarTop = sidebar.getBoundingClientRect().top;
					const headingTop = heading.getBoundingClientRect().top;
					const scrollOffset = headingTop - sidebarTop - (window.innerHeight / 2 - heading.offsetHeight / 2);

					// Verhindere zu große Scrollbewegungen
					const maxScrollTop = sidebar.scrollHeight - sidebar.clientHeight;
					sidebar.scrollTop = Math.min(maxScrollTop, Math.max(0, sidebar.scrollTop + scrollOffset));
				}
			});
		});
	});

	// Event-Listener für den Close-Icon
	const closeIcon = document.querySelector('.ez-toc-close-icon');
	if (closeIcon) {
		closeIcon.addEventListener('click', () => {
			const headings = document.querySelectorAll('.ez-toc-sidebar a');
			headings.forEach(heading => heading.classList.remove('active'));

			if (previousActiveHeading) {
				previousActiveHeading.classList.add('active');
			}
		});
	}
})();

/* - Ende Sticky-Menü Resizable Überschriften; Browser allgemein - */
  • Das relevante CSS ist im Abschnitt '9. Das CSS in einem Bündel'.

Erklärungen zu den Änderungen:

  1. Verwendung von const und let: const für unveränderliche Variablen und let für veränderliche Variablen.
  2. Pfeilfunktionen: Kürzere Syntax und automatisch gebundenes this.
  3. Throttle-Funktion: Behebt den this-Kontext und verwendet moderne Syntax.
  4. Optimierung des Event-Handlers: Entfernen von mehrfachen Event-Listenern für bessere Leistung und Lesbarkeit.
  5. Code-Selbstaufruf: Wrapping des gesamten Codes in einem selbstaufrufenden Funktionsausdruck (IIFE) zur Vermeidung von globalen Variablen.

Die wichtigsten Anpassungen bestanden im dynamischen Hinzufügen des .ez-toc-sticky-title-container mit JavaScript sowie in der Sicherstellung, dass dieser Container in Firefox korrekt funktioniert. Der Container bleibt nun beim Zurückscrollen fixiert, sobald die erste Überschrift den Scrolle-Auslöse (Triggerpunkt) überschreitet, und somit am oberen Rand des Containers anhaftet. Dadurch wurde die Scroll-Logik so angepasst, dass die Hervorhebung der Überschriften und das Scrollen innerhalb der .ez-toc-sidebar auch in Firefox korrekt funktionieren.

Mit diesen Anpassungen wird der JavaScript-Code klarer, moderner und potenziell performanter.

Weitere Codes der Entwicklung (Anfänge)
/* --- Sticky-Menü Resizable Überschriften --- */

(function() {
    var lastScrollTop = 0;
    var previousActiveHeading = null;

    function updateHeadingHighlight() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        var windowHeight = window.innerHeight;
        var scrollTop = window.scrollY;
        var sidebar = document.querySelector('.ez-toc-sidebar');

        // Finde die Überschrift, die sich am nächsten am mittleren Rand des Bildschirms befindet
        var closestHeading = null;
        var closestDistance = Infinity;
        headings.forEach(function(heading) {
            var targetId = heading.getAttribute('href').substring(1);
            var targetHeading = document.getElementById(targetId);
            if (targetHeading) {
                var headingRect = targetHeading.getBoundingClientRect();
                var middleOfViewport = windowHeight / 6; // Mitte des Viewports
                var distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport); // Distanz zwischen Mitte der Überschrift und Mitte des Viewports
                var threshold = windowHeight / 2; // Schwelle für die Markierung
                if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
                    closestDistance = distanceToMiddle;
                    closestHeading = heading;
                }
            }
        });

        // Markiere die gefundene Überschrift und entferne Markierung von anderen Überschriften
        if (closestHeading) {
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            closestHeading.classList.add('active');

            // Überprüfen, ob das Menü scrollbar ist und sich der Scroller nach unten bewegen muss
            if (sidebar.scrollHeight > sidebar.clientHeight) {
                // Berechnen der Position, um die die markierte Überschrift mittig im sichtbaren Bereich zu halten
                var targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 4 - closestHeading.offsetHeight / 2);
                sidebar.scrollTop = targetPosition;
            }

            // Speichern der aktuellen aktiven Überschrift
            previousActiveHeading = closestHeading;
        }

        // Speichern des aktuellen Scrollwerts für den nächsten Durchlauf
        lastScrollTop = scrollTop;
    }

    document.addEventListener('scroll', updateHeadingHighlight);
    document.addEventListener('DOMContentLoaded', updateHeadingHighlight);

    // Event-Listener für das Anklicken eines Menülinks
    document.addEventListener('DOMContentLoaded', function() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        headings.forEach(function(heading) {
            heading.addEventListener('click', function(event) {
                // Entferne die aktive Markierung von allen Überschriften im Menü, außer dem Schließenkreuz
                if (!this.classList.contains('ez-toc-close-icon')) {
                    headings.forEach(function(heading) {
                        heading.classList.remove('active');
                    });

                    // Füge die aktive Markierung zur angeklickten Überschrift hinzu
                    this.classList.add('active');

                    // Verhindere den Standardverhalten des Links (z. B. das Scrollen zur Ankerposition)
                    event.preventDefault();
                }
            });
        });
    });

    // Event-Listener für das Klicken auf das Schließenkreuz
    var closeIcon = document.querySelector('.ez-toc-close-icon');
    if (closeIcon) {
        closeIcon.addEventListener('click', function() {
            // Entferne die aktive Markierung von allen Überschriften im Menü
            var headings = document.querySelectorAll('.ez-toc-sidebar a');
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            // Wiederherstellen der vorherigen aktiven Überschrift, falls vorhanden
            if (previousActiveHeading) {
                previousActiveHeading.classList.add('active');
            }
        });
    }
})();

/* Ende Sticky-Menü Resizable Überschriften */

Folgend: Ausblenden der letzten Überschrift, was mir letztens nicht mehr so konform erschien und zusätzlichen Code erforderte.

Dasselbe JavaScript mit der Ergänzung, dass die Markierung der letzten Überschrift ausgeblendet wird, wenn das Element .navigation.post-navigation in den Viewport gelangt. Dieser Selektor kann individuell angepasst werden.

/* - Sticky-Menü Resizable Überschriften – ohne Markierung ab '.navigation.post-navigation' - */

(function() {
    var lastScrollTop = 0;
    var previousActiveHeading = null;

    function updateHeadingHighlight() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        var windowHeight = window.innerHeight;
        var scrollTop = window.scrollY;
        var sidebar = document.querySelector('.ez-toc-sidebar');

        // Finde die Überschrift, die sich am nächsten am mittleren Rand des Bildschirms befindet
        var closestHeading = null;
        var closestDistance = Infinity;
        headings.forEach(function(heading) {
            var targetId = heading.getAttribute('href').substring(1);
            var targetHeading = document.getElementById(targetId);
            if (targetHeading) {
                var headingRect = targetHeading.getBoundingClientRect();
                var middleOfViewport = windowHeight / 6; // Mitte des Viewports
                var distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport); // Distanz zwischen Mitte der Überschrift und Mitte des Viewports
                var threshold = windowHeight / 4; // Schwelle für die Markierung. 4 = weiter oben,  2 = mittig
                if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
                    closestDistance = distanceToMiddle;
                    closestHeading = heading;
                }
            }
        });

        // Markiere die gefundene Überschrift und entferne Markierung von anderen Überschriften
        if (closestHeading) {
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            closestHeading.classList.add('active');

            // Überprüfen, ob das Menü scrollbar ist und sich der Scroller nach unten bewegen muss
            if (sidebar.scrollHeight > sidebar.clientHeight) {
                // Berechnen der Position, um die die markierte Überschrift mittig im sichtbaren Bereich zu halten
                var targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 4 - closestHeading.offsetHeight / 2);
                sidebar.scrollTop = targetPosition;
            }

            // Speichern der aktuellen aktiven Überschrift
            previousActiveHeading = closestHeading;
        }

        // Speichern des aktuellen Scrollwerts für den nächsten Durchlauf
        lastScrollTop = scrollTop;

        // Überprüfen, ob der Benutzer den Inhalt am Ende erreicht hat
        if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
            removeLastHeadingHighlight();
        }

        // Überprüfen, ob der Benutzer zu den ".navigation.post-navigation"-Elementen scrollt. Der Selektor des Elements kann angepasst werden.
        var crpRelatedElements = document.querySelectorAll('.navigation.post-navigation');
        crpRelatedElements.forEach(function(element) {
            var elementRect = element.getBoundingClientRect();
            if (elementRect.top >= 0 && elementRect.bottom <= windowHeight) {
                removeLastHeadingHighlight();
            }
        });
    }

    function removeLastHeadingHighlight() {
        if (previousActiveHeading) {
            previousActiveHeading.classList.remove('active');
        }
    }

    document.addEventListener('scroll', updateHeadingHighlight);
    document.addEventListener('DOMContentLoaded', updateHeadingHighlight);

    // Event-Listener für das Anklicken eines Menülinks
    document.addEventListener('DOMContentLoaded', function() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        headings.forEach(function(heading) {
            heading.addEventListener('click', function(event) {
                // Entferne die aktive Markierung von allen Überschriften im Menü, außer dem Schließenkreuz
                if (!this.classList.contains('ez-toc-close-icon')) {
                    headings.forEach(function(heading) {
                        heading.classList.remove('active');
                    });

                    // Füge die aktive Markierung zur angeklickten Überschrift hinzu
                    this.classList.add('active');

                    // Verhindere den Standardverhalten des Links (z. B. das Scrollen zur Ankerposition)
                    event.preventDefault();
                }
            });
        });
    });

    // Event-Listener für das Klicken auf das Schließenkreuz
    var closeIcon = document.querySelector('.ez-toc-close-icon');
    if (closeIcon) {
        closeIcon.addEventListener('click', function() {
            // Entferne die aktive Markierung von allen Überschriften im Menü
            var headings = document.querySelectorAll('.ez-toc-sidebar a');
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            // Wiederherstellen der vorherigen aktiven Überschrift, falls vorhanden
            if (previousActiveHeading) {
                previousActiveHeading.classList.add('active');
            }
        });
    }
})();

/* Ende Sticky-Menü Resizable Überschriften – ohne Markierung ab '.navigation.post-navigation' */

Allgemein für das Sticky-Menü ist zu beachten: Die Markierung erfolgt nicht, wenn der Artikel nicht abgespeichert wurde. Das geht aus dem Plug-in selbst so hervor und die Überschriften werden in der reinen Vorschau nicht markiert, solange der Artikel nicht abgespeichert wurde. Diese Regelung bleibt bestehen, selbst wenn die Überschrift nachträglich angepasst wurde. In der Vorschau funktioniert dies möglicherweise nicht wie erwartet, da die Änderungen noch nicht gespeichert wurden.

Überschriften innerhalb von Scrollern

Überschriften innerhalb von Scrollern werden nicht alle markiert. Das Plug-in kann jedoch auf diese Überschriften zugreifen, sodass durch Anklicken im Inhaltsverzeichnis zur entsprechenden Überschrift im Scroller navigiert wird. Dieses Problem ist bei Scrollern zu berücksichtigen und auf etwaige Überschriften unterhalb deren sichtbaren Bereichs zu verzichten, oder anderer kreativen Lösung wie der Ausschluss dieser Überschriften.

Erprobung anderer Ansätze

Bei Scrollen nach oben sollte die vorhergehende Überschrift markiert werden, wenn die aktuelle Überschrift unten aus dem visuellen Bereich ist. Das wäre für länger Abschnitte der vorherigen Überschrift sehr passend. Das ist nicht so erfolgreich, deswegen sind wir mit dem aktuellen JS sehr zufrieden!

8. Link-Hinweis im Sticky-Menü

Für Personen, die das Menü auch verwenden möchten, um einen Link unterhalb des Menüs zu platzieren, zum Beispiel als Hinweis auf das "Easy Table of Contents" Plug-in.

/* --- Sticky-Menü ein Link-Hinweis --- */

window.addEventListener('load', function() {
    var tocSidebar = document.querySelector('.ez-toc-sidebar');

    // Überprüfen, ob das ez-toc-sidebar-Element existiert
    if (tocSidebar) {
        // Erstellen des Links
        var tocLink = document.createElement('a');
        tocLink.setAttribute('href', 'https://wegerl.at/wordpress-inhaltsverzeichnis/#sticky-toc-anpassen');
        tocLink.setAttribute('title', 'Sticky-Menü Überschriften markieren'); // Titel hinzufügen
        tocLink.textContent = 'Easy Table of Content';
        tocLink.classList.add('sticky-link-class'); // Hier "sticky-link-class" durch den gewünschten Klassennamen ersetzen

        // Erstellen des Dashicon-Elements
        var dashiconSpan = document.createElement('span');
        dashiconSpan.classList.add('dashicons', 'dashicons-admin-links');

        // Fügen Sie das Dashicon-Element vor dem Link hinzu
        tocLink.insertBefore(dashiconSpan, tocLink.firstChild);

        // Fügen Sie den Link am Ende des ez-toc-sidebar-Elements hinzu
        tocSidebar.appendChild(tocLink);
    }
});

/* Ende Sticky-Menü ein Link-Hinweis */

Organisieren Sie Ihre Inhaltsverzeichnisse im Handumdrehen und mit Leichtigkeit dank Easy Table of Contents Pro!

9. CSS in einem Bündel

Hier ist nun der gesamte CSS von oben in einem einzigen Code-Block zusammengefasst. Wir hoffen, dass dies dir die Arbeit erleichtert und du schnell und einfach nutzen kannst.

  • Das folgende CSS 'Sticky TOC gesamt' ist mit dem Code 'Resizable Überschriften; Browser allgemein' kompatibel:
/* === Sticky TOC gesamt === */

/* Toc Sticky aus- einblenden normal 20/14 */
.ez-toc-sticky-fixed.hide {
    display: block;
}

/* Sticky ausblenden und JS einblenden */
.ez-toc-sticky {
    display: none;
}

/* Index-Button */
.ez-toc-open-icon span.text {
    font-size: 0.9rem;
}

.ez-toc-open-icon {
    color: #535780;
    background: #fafafa;
    z-index: 9 !important;
}

.ez-toc-open-icon:hover {
    color: #cd5606 !important;
}
/* Ende Index-Button */

/* Sticky TOC Menü langsam einblenden */
.ez-toc-sticky-fixed {
    opacity: 0;
    transition: width 1s ease, opacity 2s ease;
}

.ez-toc-sticky-fixed.show {
    opacity: 1;
}

@keyframes rollInFromLeft {
    from {
        transform: translateX(-100%);
    }
    to {
        transform: translateX(0);
    }
}

.ez-toc-sticky-fixed.show {
    animation: rollInFromLeft 1.3s ease forwards;
}
/* Ende Sticky TOC Menü langsam einblenden */

/* --- Sticky Container ---  */
.ez-toc-sticky-title-container {
    display: block !important;
    position: sticky !important;
    float: left;
    background: #fff !important;
    margin-left: 0px !important;
}

.ez-toc-sticky-title {
    display: block !important;
    color: #4f5279;
    height: 5px;
    margin-left: -10px !important;
    width: 100%;
}

.ez-toc-sticky-title.visible::after {
    content: "Scrollen";
    position: absolute;
    right: 20%;
    background-color: rgba(0, 0, 0, 0.5);
    color: #ffffff;
    padding: 0px 4px;
    border-radius: 3px;
    font-size: 12px;
    top: 15px;
    margin-left: 0px !important;
}

.ez-toc-sticky-fixed .ez-toc-close-icon {
    display: block !important;
    position: absolute !important;
    top: 10px;
    right: 10px;
    font-size: 25px !important;
    color: #4f5279;
}

#ez-toc-sticky-container a:visited,
#ez-toc-container a:visited {
    color: #6f6f6f;
}
/* Ende Sticky Container  */

/* leichter Rahemen ... */
.ez-toc-sidebar {
    padding-top: 0px !important;
    font-size: 90% !important;
    border-top: 8px solid #f5f2f0;
    border-bottom: 8px solid #f5f2f0;
    border-right: 4px solid #f5f2f0;
}

/* Handler CSS */
.resize-handle-icon {
    position: relative;
}

.resize-handle-icon::after {
    content: ""; /* Pseudo-Element für die Schraffierung */
    position: absolute;
    bottom: 0; /* Am unteren Rand des Elternelements positionieren */
    right: 0;
    width: 100%;
    height: 100%;
    background-image: linear-gradient(
        45deg,
        gray 25%,
        transparent 25%,
        transparent 75%,
        gray 75%
    );
}
/* Ende Handler CSS */

/* CSS Sticky TOC Resizable Überschriften */
.ez-toc-sidebar a.active {
    font-weight: 500;
    background-color: #7f7f7f;
    color: #fff !important;
    padding: 0px 5px;
    border-radius: 4px;
}

.ez-toc-sidebar a:focus {
    outline: none;
}
/* Ende CSS Sticky TOC Resizable Überschriften */

/* Verstecken der Scrollleisten in Webkit-basierten Browsern (Chrome, Safari) */
.ez-toc-sidebar::-webkit-scrollbar {
    display: none;
}

/* Verstecken der Scrollleisten in Firefox */
@-moz-document url-prefix() {
    .ez-toc-sidebar {
        scrollbar-width: none;
    }
}

/* Sticky TOC Link-Hinweis */
.sticky-link-class {
    display: flex;
    float: right;
    align-items: center;
    font-size: 14px;
    margin-top: 25px;
    color: #1656b0;
    text-decoration: none;
}

.sticky-link-class:hover {
    color: #cd5606;
}

/* Fallweise: Sticky-Menü ohne Zähler, mit der relvanten ID ersetzten */
.postid-123 .ez-toc-sticky-toggle-counter nav ul li a::before {
    display: none !important;
}

.postid-456 .ez-toc-sticky-toggle-counter nav ul li a::before {
    display: none !important;
}

/* = Ende Sticky TOC = */

Bereit für Anpassungen?
Sei auf unterschiedliche Aspekte vorbereitet!

Entwicklungs-Teil gesamten Code, letzte Überschrift ausblenen:

/* --- Sticky TOC --- */

/* - Sticky-Open-Icon mit CSS ausblenden und mit JS einblenden - */

document.addEventListener("DOMContentLoaded", function() {
    // Überprüfe, ob der Container mit der Klasse "ez-toc-container" vorhanden ist
    var tocContainer = document.getElementById('ez-toc-container');
    if (tocContainer) {
        // Zeige das Sticky-Element an
        var stickyElement = document.querySelector('.ez-toc-sticky');
        if (stickyElement) {
            stickyElement.style.display = 'block';
        }
    }
});

/* Ende Sticky-Open-Icon mit CSS ausblenden und mit JS einblenden */

/* - Funktion Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses - */

function ezTOC_showBar() {
    var sidebar = document.querySelector(".ez-toc-sticky-fixed");
    if (sidebar) {
        sidebar.classList.remove("hide");
        sidebar.classList.add("show");
    }
}

function ezTOC_hideBar() {
    var sidebar = document.querySelector(".ez-toc-sticky-fixed");
    if (sidebar) {
        sidebar.classList.remove("show");
        sidebar.classList.add("hide");
        document.querySelector(".ez-toc-open-icon").style.zIndex = "9999999";
    }
}

window.addEventListener('scroll', function() {
    var container = document.getElementById('ez-toc-container');
    var sidebar = document.querySelector(".ez-toc-sticky-fixed");

    if (container && sidebar) {
        var containerRect = container.getBoundingClientRect();
        var containerTop = containerRect.top;

        // Einblenden des Sticky-Menüs, wenn der Container oben im Viewport angekommen ist
        if (containerTop <= 0) {
            ezTOC_showBar();
            sidebar.style.zIndex = "999"; // Setze den Z-Index-Wert des Sticky-Menüs
            document.querySelector(".ez-toc-open-icon").style.zIndex = "-1";
            // Entferne den Event Listener, um das automatische Einblenden zu stoppen
            window.removeEventListener('scroll', arguments.callee);
        } else {
            ezTOC_hideBar();
        }
    }
});

/* Ende Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses */

/* - Funktion Sticky-Menü vertikal zentriert - */
function centerSidebarVertically() {
    var sidebar = document.querySelector('.ez-toc-sidebar');

    if (sidebar) {
        var windowHeight = window.innerHeight; // Höhe des sichtbaren Bereichs des Bildschirms
        var sidebarHeight = sidebar.offsetHeight; // Höhe der Seitenleiste

        // Berechne die obere Position der Seitenleiste, um sie vertikal zentriert zu halten
        var topPosition = (windowHeight - sidebarHeight) / 2;

        // Setze die obere Position der Seitenleiste
        sidebar.style.top = topPosition + 'px';
    }
}

// Füge einen Event-Listener hinzu, um die Seitenleiste neu zu positionieren, wenn sich die Fenstergröße ändert
window.addEventListener('resize', centerSidebarVertically);

// Rufe die Funktion auf, um die Seitenleiste initial vertikal zentriert zu positionieren
window.onload = centerSidebarVertically;

/* Ende Sticky-Menü vertikal zentriert */

/* - Sticky Hinweis zum Scrollen - */

window.addEventListener('load', function() {
    var stickyTitle = document.querySelector('.ez-toc-sticky-title');
    var stickyContainer = document.querySelector('.ez-toc-sticky-container');

    // Überprüfen, ob sowohl der Sticky-Titel als auch der Sticky-Container existieren
    if (stickyTitle && stickyContainer) {
        // Überprüfen, ob der Inhalt des Sticky-Bereichs über 550px liegt
        if (stickyContainer.offsetHeight > 550) {
            stickyTitle.classList.add('visible');
        } else {
            stickyTitle.classList.remove('visible');
        }
    }
});

/* Ende Sticky Hinweis zum Scrollen */

/* --- Sticky-Menü mit Resizable Handles --- */

(function() {
    // Funktion zum Initialisieren des Resizable Handles
    function initResizable(element) {
        if (!element) return; // Überprüfen, ob das Element vorhanden ist

        var startX, startY, startWidth, startHeight;

        var resizeHandle = document.createElement('div');
        resizeHandle.className = 'ez-toc-resize-handle';
        resizeHandle.style.position = 'fixed';
        resizeHandle.style.bottom = '0';
        resizeHandle.style.right = '0';
        resizeHandle.style.width = '20px';
        resizeHandle.style.height = '20px';
        resizeHandle.style.background = '#ddd';
        resizeHandle.style.cursor = 'nwse-resize';
        resizeHandle.classList.add('resize-handle-icon');

        element.appendChild(resizeHandle);

        function startResize(e) {
            e.preventDefault();
            startX = e.clientX;
            startY = e.clientY;
            startWidth = element.getBoundingClientRect().width;
            startHeight = element.getBoundingClientRect().height;
            document.addEventListener('mousemove', doResize);
            document.addEventListener('mouseup', stopResize);
        }

        function doResize(e) {
            var newWidth = startWidth + (e.clientX - startX);
            var newHeight = startHeight + (e.clientY - startY);
            newWidth = Math.max(newWidth, 300);
            newHeight = Math.max(newHeight, 600);
            newWidth = Math.min(newWidth, 500);
            element.style.width = newWidth + 'px';
            element.style.height = newHeight + 'px';

            adjustFontSize(newWidth); // Schriftgröße anpassen
        }

        function stopResize() {
            document.removeEventListener('mousemove', doResize);
            document.removeEventListener('mouseup', stopResize);
        }

        resizeHandle.addEventListener('mousedown', startResize);
    }

    function adjustFontSize(width) {
        var links = document.querySelectorAll('.ez-toc-sticky-list');
        if (width >= 400) { // Bedingung, um die Schriftgröße anzupassen
            links.forEach(function(link) {
                link.style.fontSize = '16px';
            });
        } else {
            links.forEach(function(link) {
                link.style.fontSize = ''; // Rücksetzen auf Standardwert
            });
        }
    }

    var sidebar = document.querySelector('.ez-toc-sidebar');
    initResizable(sidebar);

    // Event-Listener zum Überwachen der Größe des Browserfensters hinzufügen
    window.addEventListener('resize', function() {
        if (sidebar) {
            var width = sidebar.getBoundingClientRect().width;
            adjustFontSize(width); // Schriftgröße beim Ändern der Fenstergröße anpassen
        }
    });
})();

/* Ende Sticky-Menü mit Resizable Handles */

/* --- Sticky-Menü bleibt geöffnet, siehe (ez-toc-sticky.min.js) --- */

/* - Sticky-Menü Resizable Überschriften und ohne Markierung ab '.navigation.post-navigation' - */

(function() {
    var lastScrollTop = 0;
    var previousActiveHeading = null;

    function updateHeadingHighlight() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        var windowHeight = window.innerHeight;
        var scrollTop = window.scrollY;
        var sidebar = document.querySelector('.ez-toc-sidebar');

        // Finde die Überschrift, die sich am nächsten am mittleren Rand des Bildschirms befindet
        var closestHeading = null;
        var closestDistance = Infinity;
        headings.forEach(function(heading) {
            var targetId = heading.getAttribute('href').substring(1);
            var targetHeading = document.getElementById(targetId);
            if (targetHeading) {
                var headingRect = targetHeading.getBoundingClientRect();
                var middleOfViewport = windowHeight / 6; // Mitte des Viewports
                var distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport); // Distanz zwischen Mitte der Überschrift und Mitte des Viewports
                var threshold = windowHeight / 4; // Schwelle für die Markierung. 4 = weiter oben,  2 = mittig
                if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
                    closestDistance = distanceToMiddle;
                    closestHeading = heading;
                }
            }
        });

        // Markiere die gefundene Überschrift und entferne Markierung von anderen Überschriften
        if (closestHeading) {
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            closestHeading.classList.add('active');

            // Überprüfen, ob das Menü scrollbar ist und sich der Scroller nach unten bewegen muss
            if (sidebar.scrollHeight > sidebar.clientHeight) {
                // Berechnen der Position, um die die markierte Überschrift mittig im sichtbaren Bereich zu halten
                var targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 4 - closestHeading.offsetHeight / 2);
                sidebar.scrollTop = targetPosition;
            }

            // Speichern der aktuellen aktiven Überschrift
            previousActiveHeading = closestHeading;
        }

        // Speichern des aktuellen Scrollwerts für den nächsten Durchlauf
        lastScrollTop = scrollTop;

        // Überprüfen, ob der Benutzer den Inhalt am Ende erreicht hat
        if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
            removeLastHeadingHighlight();
        }

        // Überprüfen, ob der Benutzer zu den ".navigation.post-navigation"-Elementen scrollt. Der Selektor des Elements kann angepasst werden.
        var crpRelatedElements = document.querySelectorAll('.navigation.post-navigation');
        crpRelatedElements.forEach(function(element) {
            var elementRect = element.getBoundingClientRect();
            if (elementRect.top >= 0 && elementRect.bottom <= windowHeight) {
                removeLastHeadingHighlight();
            }
        });
    }

    function removeLastHeadingHighlight() {
        if (previousActiveHeading) {
            previousActiveHeading.classList.remove('active');
        }
    }

    document.addEventListener('scroll', updateHeadingHighlight);
    document.addEventListener('DOMContentLoaded', updateHeadingHighlight);

    // Event-Listener für das Anklicken eines Menülinks
    document.addEventListener('DOMContentLoaded', function() {
        var headings = document.querySelectorAll('.ez-toc-sidebar a');
        headings.forEach(function(heading) {
            heading.addEventListener('click', function(event) {
                // Entferne die aktive Markierung von allen Überschriften im Menü, außer dem Schließenkreuz
                if (!this.classList.contains('ez-toc-close-icon')) {
                    headings.forEach(function(heading) {
                        heading.classList.remove('active');
                    });

                    // Füge die aktive Markierung zur angeklickten Überschrift hinzu
                    this.classList.add('active');

                    // Verhindere den Standardverhalten des Links (z. B. das Scrollen zur Ankerposition)
                    event.preventDefault();
                }
            });
        });
    });

    // Event-Listener für das Klicken auf das Schließenkreuz
    var closeIcon = document.querySelector('.ez-toc-close-icon');
    if (closeIcon) {
        closeIcon.addEventListener('click', function() {
            // Entferne die aktive Markierung von allen Überschriften im Menü
            var headings = document.querySelectorAll('.ez-toc-sidebar a');
            headings.forEach(function(heading) {
                heading.classList.remove('active');
            });

            // Wiederherstellen der vorherigen aktiven Überschrift, falls vorhanden
            if (previousActiveHeading) {
                previousActiveHeading.classList.add('active');
            }
        });
    }
})();

/* Ende Sticky-Menü Resizable Überschriften und ohne Markierung ab '.navigation.post-navigation' */

/* - Sticky-Menü ein Link-Hinweis - */

window.addEventListener('load', function() {
    var tocSidebar = document.querySelector('.ez-toc-sidebar');

    // Überprüfen, ob das ez-toc-sidebar-Element existiert
    if (tocSidebar) {
        // Erstellen des Links
        var tocLink = document.createElement('a');
        tocLink.setAttribute('href', 'https://wegerl.at/wordpress-inhaltsverzeichnis/#sticky-toc-anpassen');
        tocLink.setAttribute('title', 'Sticky-Menü Überschriften markieren'); // Titel hinzufügen
        tocLink.textContent = 'Easy Table of Content';
        tocLink.classList.add('sticky-link-class'); // Hier "sticky-link-class" durch den gewünschten Klassennamen ersetzen

        // Erstellen des Dashicon-Elements
        var dashiconSpan = document.createElement('span');
        dashiconSpan.classList.add('dashicons', 'dashicons-admin-links');

        // Fügen Sie das Dashicon-Element vor dem Link hinzu
        tocLink.insertBefore(dashiconSpan, tocLink.firstChild);

        // Fügen Sie den Link am Ende des ez-toc-sidebar-Elements hinzu
        tocSidebar.appendChild(tocLink);
    }
});

/* Ende Sticky-Menü ein Link-Hinweis */

/* ENDE Sticky TOC */

B) Globale Anpassungen

  • Umbruch von Überschriften im Inhalt
  • Automatisches Hinzufügen eines Ankers zum Haupt-Inhaltsverzeichnis
  • Sticky-Menü das Anzeigen des Zählers deaktivieren
  • Probleme mit Sticky TOC und Twenty Fourteen

Umbruch von Überschriften im Inhalt

Überschriften können nicht einfach mit Shift und Enter umgebrochen werden, ohne dass es zu Problemen für das Inhaltsverzeichnis kommt.

Es ist immer separat mit <br> auszuzeichnen. Dies wird dann nicht responsive konform, daher sollte dies per CSS wie folgt umgesetzt werden:

/* --- Überschriften mit Zeilenumbruch --- */

@media (min-width: 700px) {
    .lange-ue {
        white-space: nowrap;
    }
}

CSS-Media-Query @media (min-width: 700px) stellt sicher, dass diese Classen nur auf Bildschirmen mit einer Mindestbreite von 700 Pixeln angewendet werden.

Der Teil ab <span class="nowrap"> wird nicht umgebrochen und in die nächste Zeile verschoben, wenn er nicht mehr genügend Platz hat, um sich vollständig innerhalb der aktuellen Textzeile auszubreiten.

Anmerkung: Die Verwendung von white-space: nowrap; auf der Ebene der Inline-Styles wäre nicht ideal, wenn du eine responsive Website erstellst, da dies die Flexibilität der Darstellung auf verschiedenen Bildschirmgrößen beeinträchtigen kann.

Durch die Verwendung der .lange-ue-Classe und die Einschränkung auf den @media-Bereich kannst du sicherstellen, dass der Zeilenumbruch nur auf größeren Bildschirmen deaktiviert wird, während er auf kleineren Bildschirmen, wie Mobilgeräten, weiterhin aktiv bleibt. Dadurch wird sichergestellt, dass die Darstellung der Überschriften auch auf mobilen Geräten gut aussieht und dass der Text entsprechend umbrochen wird, um auf den Bildschirm zu passen.

Zum Beispiel im HTML dann:

<h5 class="lange-ue">Tanzende Überschriften: <span class="nowrap">mit Zeilenumbruch-Zauber!</span></h5>

Überschriften, die umgebrochen werden sollen, werden mit der Classe lange-ue versehen und die Teile, die nicht umgebrochen werden sollen, innerhalb eines span-Tags mit der Classe nowrap.

Also die Class class="lange-ue" in den Überschriften-Tag und mit <span class="nowrap"> der Stelle, wo der visuelle Umbruch stattfindet.


Bitte beachten: dass der Link vom Inhaltsverzeichnis zur Überschrift mit Umbruch erst nach Speichern des Artikels funktioniert und nicht in der Vorschau ohne vorheriges Abspeichern ablegt. Das ist auch bei Änderungen im Nachhinein der Fall. Das geht dem Plug-in selbst so hervor und sollte immer berücksichtigt werden.


Nochmal, der Zeilenumbruch erfolgt nur, wenn der Text nach der nowrap-Classe nicht mehr in dieselbe Zeile passt. Ein Beispiel dafür ist die folgende Überschrift:

Tanzende Überschriften: mit Zeilenumbruch-Zauber!

Die Überschrift bleibt hier im Lesemodus ununterbrochen, da der Text immer noch in dieselbe Zeile passt. Wenn du jedoch über die Headerleiste in den Normalmodus wechselt und die Inhaltsbreite schmaler wird, wird die Überschrift gemäß der Class und der nowrap-Auszeichnung umbrochen.

Hier ist mein Beitrag im Support: Überschrift mit Zeilenumbruch.

Dem Haupt-Menü automatisch einen Anker setzten

Das Inhaltsverzeichnis wird automatisch mit einem Anker versehen, sodass am Ende des Artikels ein Button-Link zurück zum Verzeichnis führt.

  1. JS, um den Anker automatisch einfügen:
/* --- TOC Anker autmoatisch --- */

jQuery('#ez-toc-container').before('<div id="ih-toc"></div>');

2. JS, Funktion Scrolle zum Anker

/* --- Scrolle zum  Anker ih-toc --- */

(function($) {
    // Alle Fehlermeldungen zeigen, um Fehler zu beheben.
    "use strict";

    function zumAnkerScrollen() {
        let anker = ["#ih-toc"];

        $.each(anker, function(index, value) {
            $("a[href=\"" + value + "\"]").on("click", function(e) {
                e.preventDefault(); // Deaktiviert die generelle Funktion des angeklickten Links
                var offset = -20; // wie viel Platz oberhalb sein soll, also die Höhe der Kopfzeile + 10 oder 20.
                if ($(value).length) {
                    $('html, body').animate({
                        scrollTop: $(value).offset().top + offset
                    }, 1000); // Die Geschwindigkeit für die Animation. Hier eine Sekunde.
                }
            });
        });
    }

    // Alternative für $(document).ready({});
    $(function() {
        zumAnkerScrollen();
    });
})(jQuery);

/* Ende Scrolle zum  Anker ih-toc */

3. Zum Beispiel als Shortcode für den Button, der über die functions.php erstellt wurde:

/* --- Shortcode: mybutton --- */ 

add_shortcode('mybutton', function( $atts ) {
    extract(shortcode_atts(array(
        'text' => '',
        'link' => '#ih-toc'
    ), $atts)); 

    $html = '<a href="' . $link . '"><div class="myButton">' . $text . '</div></a>';
    return $html;    
});

/* Ende Shortcode: mybutton */ 

4. Das CSS für den Button, bspw.:

/* --- myButton CSS --- */

.myButton {
	position: relative;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
margin-bottom: 100px;
	width: 30px;
	height: 30px;
	background: -webkit-gradient(linear,0 0,0 100%,from(#a4d3ee),to(#f5f5f5));
	background: -moz-linear-gradient(top,#a4d3ee,#f5f5f5);
	box-shadow: 0 0 3px gray;
	-webkit-border-radius: 50%;
}

/* Ende myButton CSS */

Ein Klick für den Überblick – zurück zum Inhaltsverzeichnis

Siehe den Button am Ende des Beitrags, das Emblem von WP Wegerl. Dadurch scrollt man mit Anklicken zurück zum Inhaltsverzeichnis.

Sticky-Menü das Anzeigen des Zählers deaktivieren

Easy Table of Contents erlaubt es, die Standardeinstellungen für jeden Beitrag oder jede Seite unterhalb des Editors anzupassen. Es besteht auch die Möglichkeit, die Option "Hide Counter: Do not show counters for the table of contents" zu aktivieren. Beachte jedoch, dass diese Einstellung nur das Haupt-Inhaltsverzeichnis betrifft und nicht das Sticky-Menü.

Da diese Funktion wahrscheinlich weniger häufig verwendet wird, lohnt es sich, die Mühe zu machen, sie separat im CSS für jeden Beitrag festzulegen. Wenn der Zähler für das Inhaltsverzeichnis nicht angezeigt werden soll:

/* Sticky-Menü ohne Zähler */

.postid-123 .ez-toc-sticky-toggle-counter nav ul li a::before {
	display: none;
}

Das Beipiel ist diesem Beitrag im Sticky-Menü zu sehen.

Probleme mit Sticky TOC und Twenty Fourteen

In diesem Abschnitt geht es um einen CSS-Schnipsel, das zur Anpassung des Sticky-Menüs relevant ist.

Es öffnet und schließt in einem Ruck. Das Problem wurde seinerzeit gelöst. Die Lösung besteht darin, im Thema Twenty Fourteen den Regelsatz .hide {display: none;} zu überschreiben. (Zur Nachlese, siehe Support.)

  • Folgender Code ist für Theme 20/14 auch relavant, um die obigen Entwicklungen erfolgreich zu implementieren!

Dies kann entweder im Child-Theme oder im Customizer erfolgen:

/* --- Sticky TOC spezifisch 20/14 --- */

.ez-toc-sticky-fixed.hide {
    display: block;
}

Die Abenteuer des neugierigen Lesers

Eine kleine kulinarische Geschichte.

Ein neugieriger Leser taucht in die Tiefen des Inhaltsverzeichnisses ein, begierig darauf, die Geheimnisse und Wunder zu entdecken, die zwischen den Zeilen verborgen sind. Mit einem Klick beginnt sein aufregendes Abenteuer durch die mysteriöse Welt der Überschriften und Unterkapitel.

Die Entdeckung der kulinarischen Künste

In diesem Abschnitt des Inhaltsverzeichnisses stößt der Leser auf eine Vielzahl von kulinarischen Kreationen und gastronomischen Genüssen. Von verlockenden Vorspeisen bis hin zu verführerischen Desserts, jede Überschrift verspricht eine neue kulinarische Erfahrung.

Die geheimen Rezepte der Kochkunst

Während der Leser weiter in das Inhaltsverzeichnis eintaucht, stößt er auf eine Sammlung geheimer Rezepte und unerforschter Kochtechniken. Diese versteckten Schätze versprechen, seine kulinarischen Fähigkeiten zu erweitern und ihm das Geheimnis der perfekten Mahlzeit zu enthüllen.

Eine Expedition durch die Welt der Aromen

In diesem Abschnitt erlebt der Leser eine abenteuerliche Expedition durch die vielfältigen Aromen und Geschmacksrichtungen der Welt. Von exotischen Gewürzen bis hin zu vertrauten Aromen, jede Überschrift führt zu einem neuen Geschmackserlebnis und einer unvergesslichen kulinarischen Reise.

Die Begegnung mit schelmischen Snacks

Hier trifft der Leser auf eine bunte Vielfalt schelmischer Snacks und verlockender Leckereien. Diese frechen Köstlichkeiten versprechen, seine Geschmacksknospen zu kitzeln und ihm ein Lächeln auf die Lippen zu zaubern, während er sich durch das Inhaltsverzeichnis navigiert.

Ein Festmahl für die Sinne: Geschichten aus der Küche

Schließlich kommt der Leser am Ende seines Abenteuers an und findet sich inmitten eines opulenten Festmahls für die Sinne wieder. Diese abschließende Überschrift lädt ihn ein, sich zurückzulehnen, zu entspannen und die Geschichten und Aromen zu genießen, die ihm das Inhaltsverzeichnis zu bieten hat.

wp wegerl.at

Der Beitrag wurde mit fachlicher Unterstützung erstellt.


Aktualisiert im Jahr 2024 Juli