Ihr bewährter Begleiter.
Viele Nutzer schätzen die vertraute Umgebung des Classic-Editors, die eine einfache und schnelle Bearbeitung ermöglicht.
Mehr Funktionen, mehr Möglichkeiten.
Der Advanced Editor erweitert den Funktionsumfang des Classic-Editors und ermöglicht es, Inhalte noch effektiver zu bearbeiten.
Der Classic-Editor für alle.
Der Classic-Editor zeichnet sich durch Stabilität und Zuverlässigkeit aus, was für professionellen Anwender von Bedeutung ist.
Der Advanced Editor für kreative Köpfe.
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
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.
… 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.
- Sticky-Open-Icon nur für Beiträge anzeigen, in denen das Hauptmenü aktiviert ist
- Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses
- Sticky-Menü vertikal zentriert
- Hinzufügen eines Scroll-Hinweises zum Sticky-Menü
- Sticky-Menü mit Resizable Handles
- Sticky-Menü bleibt geöffnet
- Resizable Überschriften: Schnelle Navigation und Übersicht 🧡
- Link-Hinweis im Sticky-Menü
- 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
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.
Ist es aber nicht. Denn mit transform: translateY(50%);
wird der folgende Handler ( Siehe Punkt "5. Handles zum Sticky-Menü") nicht mehr so richtig positioniert.
/* 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 per JavaScript erfolgen. Beachte, dies ist nur relevant wenn das Sticky-Menü keinen Handler integriert wird. Mit Handler ist folgendes nicht geeignet:
/* --- 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.
Beim Einbauen des Griffs nach Punkt 5 empfiehlt es sich sehr, anstelle von JavaScript folgendes CSS zu verwenden. Zwar wird das Element nicht perfekt für alle Bildschirmgrößen zentriert, aber die Lösung ist dennoch praktikabel:
/* --- Sticky-Toc position --- */
/* Laptop und Standard-Desktop-Auflösung (bis 1439px) */
@media (max-width: 1439px) {
.ez-toc-sidebar {
margin-top: 100px;
}
}
/* Standard-Desktop-Auflösung (1440px bis 1919px) */
@media (min-width: 1440px) and (max-width: 1919px) {
.ez-toc-sidebar {
margin-top: 200px;
}
}
/* Standard-Desktop-Auflösung (1920px bis 2559px) */
@media (min-width: 1920px) and (max-width: 2559px) {
.ez-toc-sidebar {
margin-top: 300px;
}
}
/* Große Desktop-Auflösung (ab 2560px bis 3839px) */
@media (min-width: 2560px) and (max-width: 3839px) {
.ez-toc-sidebar {
margin-top: 400px;
}
}
/* Große Desktop-Auflösung (ab 3840px) */
@media (min-width: 3840px) {
.ez-toc-sidebar {
margin-top: 600px;
}
}
/* - Ende Sticky-Toc position - */
Es wurden unterschiedliche Versuche durchgeführt, aber es blieb nur die Möglichkeit, mit Margin zu arbeiten.
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. Dies ist nicht nur für größere Bildschirme konform, sondern auch aufgrund des Scrollverhaltens relativ, da eventuell die Überschriften unter dem Overflow verschwinden. Damit ist auch sichergestellt, dass das Menü auf größeren Bildschirmen perfekt bedienbar ist.
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 + Safari Sticky-Handler Positionierung --- */
(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);
// Safari Sticky-Handler Positionierung
function safariStickyHandlerFix() {
if (navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome')) {
// Funktion zur Anpassung der Handler-Position
function positionHandle() {
resizeHandle.style.position = 'absolute'; // Temporär ändern
resizeHandle.offsetHeight; // Forced Reflow
resizeHandle.style.position = 'fixed'; // Endposition
}
// IntersectionObserver einrichten
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setTimeout(positionHandle, 500); // Zeitverzögerung für Safari-Reflow
}
});
});
// Beobachten des Handlers
observer.observe(resizeHandle);
}
}
safariStickyHandlerFix(); // Safari-spezifischer Aufruf zur Handler-Positionierung
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 - */
Das CSS für den Handler:
/* --- 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 - */
Anmerkung zur Positionierung des Griffs: Aufgrund einer vertikalen Zentrierung des Sticky-Menüs würde der Griff nicht in der rechten unteren Ecke platziert.
Verworfen
Dies kann durch eine Anpassung mit JavaScript und CSS korrigiert werden? Allerdings ist dies nicht optimal, da sich die Positionierung des Handlers an der Fenstergröße orientiert. Daher ist auch diese Lösung ungeeignet.
Das JavaScript ist für die Browser relevant, da diese sich heute oft nicht allein über CSS gezielt ansprechen lassen, ohne gegenseitige Beeinflussungen hervorzurufen. Zwar funktionieren Chrome und Firefox einwandfrei mit CSS-Selektoren, aber in Kombination mit anderen Browsern kommt es zu Überschneidungen. Aus diesem Grund haben wir uns für eine konsistente Implementierung entschieden, bei der die fünf Browser jeweils durch JavaScript erkannt und gezielt angesprochen werden.
Hier ist das CSS des misslungenen Versuchs:
/* --- "Handler" Browser spezifisch --- */
/* Chrome spezifisch */
.chrome-browser .ez-toc-resize-handle {
margin-bottom: -77px !important;
}
/* Firefox spezifisch */
.firefox-browser .ez-toc-resize-handle {
margin-bottom: -95px !important;
}
/* Edge spezifisch */
.edge-browser .ez-toc-resize-handle {
margin-bottom: -95px;
}
/* Safari spezifisch */
.safari-browser .ez-toc-resize-handle {
margin-bottom: -86px !important;
}
/* Opera spezifisch */
.opera-browser .ez-toc-resize-handle {
margin-bottom: -89px !important;
}
/* - Ende "Handler" Browser spezifisch - */
Anmerkung: In diesem Kontext verwenden Firefox und Edge dasselbe Styling, obwohl sie unterschiedliche Rendering-Engines haben.
- Das JS zum Ansprechen der Browser findet sich im Beitrag:
In diesem Beitrag wird gezeigt, wie browser-spezifische Stile mit JavaScript effektiv angewendet werden können. Das ist besonders nützlich, wenn sich Browser nicht allein über CSS ... weiterlesen
Der vorhergende, überholte Code:
/* --- 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 */
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()
.
Eine Bedingung für die "Resizable Überschriften"
Bedingung für die "Resizable Überschriften:
Die Bedingung für die Funktionalität ist, dass in der Plug-in-Einstellung unter 'Allgemeines' die Option 'Exclude href from URL' nicht aktiviert ist.
Somit ist die ID als Überschrift in der URL angehängt. Falls man jedoch die Adresszeile ohne die ID in der URL haben möchte:
/* --- Die ID aus der URL nach dem Klicken auf einen Menüpunkt zu entfernen --- */
(() => {
const removeIdFromUrl = () => {
const currentUrl = window.location.href;
// Überprüfen, ob die URL eine ID enthält
if (currentUrl.includes('#')) {
// URL bis zum '#' extrahieren
const newUrl = currentUrl.split('#')[0];
// Die URL ohne ID zurücksetzen, ohne die Seite neu zu laden
window.history.replaceState(null, '', newUrl);
}
};
// Alle Links im Inhaltsverzeichnis ansprechen
const tocLinks = document.querySelectorAll('.ez-toc-list a');
tocLinks.forEach(link => {
link.addEventListener('click', (event) => {
// ID sofort entfernen, nachdem der Link angeklickt wurde
removeIdFromUrl();
});
});
// Auf das Hash-Änderungsevent reagieren
window.addEventListener('hashchange', removeIdFromUrl);
})();
/* - Ende die ID aus der URL nach dem Klicken auf einen Menüpunkt zu entfernen - */
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 */
Aufgrund der besonderen Handhabung bestimmter CSS- und JavaScript-Funktionalitäten in Firefox war es eine Herausforderung, eine Lösung zu finden:
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 auch mit Audio! – als Dank für die Erfindung der 'Resizable Überschriften' und zur Präsentation des JS durch ChatGPT.
"Der Herr hat gewonnen" (The Lord has won), bereitgestellt von Oleksii_Kalyna.
Sticky-Menü-Resizable-Überschriften_v1.0.2.js, alles inklusive, gleich wie hier:
/**
* Sticky-Menü: Resizable-Überschriften für die Browser-Navigation
* Version: 1.0.2
* Autor: Team WP Wegerl.at
* Lizenz: GPL-3.0+
* Letzte Aktualisierung: 2024-10-25
*
* Beschreibung:
* Dieses Skript implementiert ein Sticky-Menü, das ein Inhaltsverzeichnis (TOC) hervorhebt und die Benutzererfahrung durch eine dynamische Scrollsteuerung verbessert.
* Die aktive Überschrift im Inhaltsverzeichnis wird basierend auf der Scrollposition hervorgehoben, und der Container mit der Überschrift bleibt sticky, wenn sich der Benutzer durch die Seite scrollt.
*
* Funktionsweise:
* 1. Beim Scrollen oder Klicken auf eine Überschrift wird überprüft, welche Überschrift der Mitte des Bildschirms am nächsten liegt.
* 2. Diese Überschrift wird hervorgehoben, und das Inhaltsverzeichnis scrollt, um die aktive Überschrift sichtbar zu halten.
* 3. Ein Sticky-Container wird verwendet, um die aktuelle Position der Überschrift auf der Seite anzuzeigen, wenn der Benutzer scrollt.
* 4. Beim Klicken auf einen TOC-Link wird das Ziel-Element in den sichtbaren Bereich gescrollt, und die Überschrift wird hervorgehoben.
* 6. Die Sticky-Überschrift passt sich dynamisch an die Position der aktuellen Überschrift auf der Seite an und bleibt im oberen Bereich des Bildschirms sichtbar.
*
* Features:
* - Automatische Hervorhebung der Überschrift, die der Mitte des Viewports am nächsten liegt.
* - Smooth Scrolling beim Klicken auf eine Überschrift.
* - Dynamisches Sticky-Menü, das beim Scrollen anzeigt, welche Überschrift aktuell im Sichtfeld ist.
* - Unterstützung für "Throttling" von Scroll-Events zur Leistungsoptimierung.
* - Unterstützung von Close-Icons für manuelles Schließen des Menüs.
*
* Ereignisse:
* - Scroll-Event: Aktiviert das Hervorheben der Überschrift basierend auf der Scrollposition.
* - DOMContentLoaded: Initialisiert das Menü und registriert die Event-Listener für Navigation.
* - Click-Event: Ermöglicht das Navigieren zu Überschriften im Inhaltsverzeichnis (Smooth Scrolling).
*
* Kompatibilität:
* - Funktioniert in modernen Browsern und bietet eine optimierte Nutzererfahrung auf Desktop-Geräten.
*
* Hinweis: Das Skript erfordert eine Struktur mit Überschriften, die durch ein Inhaltsverzeichnis (TOC) verlinkt sind, sowie die entsprechende CSS-Klasse `.ez-toc-sidebar` für das TOC.
*/
/* === Sticky TOC === */
document.addEventListener("DOMContentLoaded", function() {
// Überprüfen, ob die Seite in einem iframe geladen ist
if (window.self !== window.top) {
// Wenn es ein iframe ist, blende die Sticky-Elemente aus
var stickyIcon = document.querySelector('.ez-toc-open-icon');
var stickySidebar = document.querySelector('.ez-toc-sidebar');
if (stickyIcon) {
stickyIcon.style.display = 'none';
}
if (stickySidebar) {
stickySidebar.style.display = 'none';
}
}
});
/* --- 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';
}
}
// Funktion zum Handhaben des Sticky-Containers
const handleStickyContainer = () => {
const stickyContainer = document.querySelector('.ez-toc-sticky-title-container');
const stickyTitle = stickyContainer ? stickyContainer.querySelector('.ez-toc-sticky-title') : null;
if (stickyContainer) {
// 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.padding = '10px'; // Anpassbare Padding
// Optionaler Schatten für bessere Sichtbarkeit
// stickyContainer.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
}
};
// Aufrufen der Sticky-Container Funktion beim Laden
handleStickyContainer();
});
/* - Ende Sticky-Open-Icon mit CSS ausblenden und mit JS einblenden - */
/* --- 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";
}
}
// U.a. Überprüfung, ob das automatische Einblenden deaktiviert wurde. Das Deaktiviert das automatische Einblenden des Sticky-Menüs " var disableAutoShow = true; "
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;
// Überprüfung, ob das automatische Einblenden deaktiviert wurde
if (typeof disableAutoShow === 'undefined' || !disableAutoShow) {
if (containerTop <= 0) {
ezTOC_showBar();
sidebar.style.zIndex = "999";
document.querySelector(".ez-toc-open-icon").style.zIndex = "-1";
window.removeEventListener('scroll', arguments.callee);
} else {
ezTOC_hideBar();
}
}
}
});
/* - Ende Sticky-Menü-Einblendung beim Erreichen des Inhaltsverzeichnisses - */
/* --- 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 + Safari Sticky-Handler Positionierung --- */
(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);
// Safari Sticky-Handler Positionierung
function safariStickyHandlerFix() {
if (navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome')) {
// Funktion zur Anpassung der Handler-Position
function positionHandle() {
resizeHandle.style.position = 'absolute'; // Temporär ändern
resizeHandle.offsetHeight; // Forced Reflow
resizeHandle.style.position = 'fixed'; // Endposition
}
// IntersectionObserver einrichten
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setTimeout(positionHandle, 500); // Zeitverzögerung für Safari-Reflow
}
});
});
// Beobachten des Handlers
observer.observe(resizeHandle);
}
}
safariStickyHandlerFix(); // Safari-spezifischer Aufruf zur Handler-Positionierung
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ü Resizable Überschriften; Browser allgemein --- */
(function() {
// Funktion zum Markieren von Überschriften, die spezifisch für Safari, Chrome und andere Browser funktioniert
function updateHeadingHighlightNoFirefox() {
var headings = document.querySelectorAll('.ez-toc-sidebar a');
var windowHeight = window.innerHeight;
var scrollTop = window.scrollY;
var sidebar = document.querySelector('.ez-toc-sidebar');
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;
var distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport);
var threshold = windowHeight / 4;
if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
closestDistance = distanceToMiddle;
closestHeading = heading;
}
}
});
if (closestHeading) {
headings.forEach(function(heading) {
heading.classList.remove('active');
});
closestHeading.classList.add('active');
if (sidebar.scrollHeight > sidebar.clientHeight) {
var targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 6 - closestHeading.offsetHeight / 2);
sidebar.scrollTop = targetPosition;
}
}
lastScrollTop = scrollTop;
}
// Überprüfen, ob der Browser nicht Firefox ist
if (typeof InstallTrigger === 'undefined') {
// Allgemeiner Scroll-Listener
document.addEventListener('scroll', updateHeadingHighlightNoFirefox);
document.addEventListener('DOMContentLoaded', updateHeadingHighlightNoFirefox);
// Click-Event für das Menü
document.addEventListener('DOMContentLoaded', function() {
var headings = document.querySelectorAll('.ez-toc-sidebar a');
headings.forEach(function(heading) {
heading.addEventListener('click', function(event) {
if (!this.classList.contains('ez-toc-close-icon')) {
headings.forEach(function(heading) {
heading.classList.remove('active');
});
this.classList.add('active');
event.preventDefault();
}
});
});
});
var closeIcon = document.querySelector('.ez-toc-close-icon');
if (closeIcon) {
closeIcon.addEventListener('click', function() {
var headings = document.querySelectorAll('.ez-toc-sidebar a');
headings.forEach(function(heading) {
heading.classList.remove('active');
});
});
}
// Safari-spezifische Anpassungen
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
console.log('Safari detected: applying specific adjustments');
// Hier könnten zusätzliche Safari-Anpassungen vorgenommen werden
}
}
})();
/* - Ende Sticky-Menü Resizable Überschriften; Browser allgemein - */
/* --- Sticky-Menü Resizable Überschriften; Firefox-Browser --- */
(function() {
// Funktion zum Markieren von Überschriften, die spezifisch für Firefox funktioniert
function updateHeadingHighlightFirefox() {
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;
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;
const distanceToMiddle = Math.abs(headingRect.top + headingRect.height / 2 - middleOfViewport);
const threshold = windowHeight / 4;
if (distanceToMiddle < closestDistance && distanceToMiddle < threshold && headingRect.top >= 0 && headingRect.bottom <= windowHeight) {
closestDistance = distanceToMiddle;
closestHeading = heading;
}
}
});
if (closestHeading) {
headings.forEach(heading => heading.classList.remove('active'));
closestHeading.classList.add('active');
if (sidebar.scrollHeight > sidebar.clientHeight) {
const targetPosition = closestHeading.offsetTop - sidebar.offsetTop - (windowHeight / 6 - closestHeading.offsetHeight / 2);
sidebar.scrollTop = targetPosition;
}
previousActiveHeading = closestHeading;
}
lastScrollTop = window.scrollY;
};
window.addEventListener('scroll', updateActiveHeading);
if (stickyContainer && previousActiveHeading) {
const stickyRect = stickyContainer.getBoundingClientRect();
const activeHeadingRect = previousActiveHeading.getBoundingClientRect();
if (activeHeadingRect.top < windowHeight && activeHeadingRect.bottom > 0) {
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';
stickyContainer.style.display = 'block';
stickyContainer.style.padding = '10px';
} else {
stickyContainer.style.display = 'none';
}
}
lastScrollTop = scrollTop;
};
const throttle = (func, limit) => {
let lastFunc;
let lastRan;
return function(...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();
}
}, Math.max(limit - (Date.now() - lastRan), 0));
}
};
};
const throttledScroll = throttle(() => {
}, 200);
window.addEventListener('scroll', throttledScroll);
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);
const maxScrollTop = sidebar.scrollHeight - sidebar.clientHeight;
sidebar.scrollTop = Math.min(maxScrollTop, Math.max(0, sidebar.scrollTop + scrollOffset));
}
});
});
});
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');
}
});
}
// Firefox-spezifische Anpassungen
const sidebar = document.querySelector('.ez-toc-sidebar');
sidebar.style.position = 'sticky'; // Stelle sicher, dass Sticky-Verhalten aktiv ist
sidebar.style.top = '0'; // Das Menü haftet am oberen Rand des Viewports
}
// Nur für Firefox den Code ausführen
if (typeof InstallTrigger !== 'undefined') {
updateHeadingHighlightFirefox();
}
})();
/* - Ende Sticky-Menü Resizable Überschriften; Firefox-Browser - */
/* --- 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 = 'Sticky-TOC (Resizable)';
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('genericon', 'genericon-link');
// 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);
// Hinweis hinzufügen: T = Toc ein- ausblenden
var tocHint = document.createElement('div');
tocHint.innerHTML = '<span style="font-size: 11px;">T = Toc ein- ausblenden</span>';
tocHint.classList.add('toc-hint-class'); // Optional: Hier "toc-hint-class" durch den gewünschten Klassennamen ersetzen
// Fügen Sie den Hinweis unter dem Link hinzu
tocSidebar.appendChild(tocHint);
}
});
/* Ende Sticky TOC Link-Hinweis */
/* = ENDE Sticky TOC = */
- Das relevante CSS ist im Abschnitt '9. Das CSS in einem Bündel'.
Der gegebene Code verwendet kein jQuery, sondern ausschließlich Vanilla JavaScript, also nativen JavaScript-Code, der direkt im Browser ausgeführt wird. Das bedeutet, dass jQuery nicht erforderlich ist, um diesen Code auszuführen.
Der Code basiert auf Standard-DOM-Methoden wie querySelector
, addEventListener
und getBoundingClientRect
, die in modernen Browsern unterstützt werden. Daher gibt es keine speziellen Bibliotheken oder Frameworks, die zusätzlich eingebunden werden müssen.
Das bedeutet, dass dieser Code problemlos ohne jQuery oder andere Abhängigkeiten funktioniert, solange der Browser moderne JavaScript-Funktionen unterstützt.
Erklärungen zu den Änderungen:
- Verwendung von
const
undlet
:const
für unveränderliche Variablen undlet
für veränderliche Variablen. - Pfeilfunktionen: Kürzere Syntax und automatisch gebundenes
this
. - Throttle-Funktion: Behebt den
this
-Kontext und verwendet moderne Syntax. - Optimierung des Event-Handlers: Entfernen von mehrfachen Event-Listenern für bessere Leistung und Lesbarkeit.
- 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-sticky-title-container .ez-toc-close-icon {
display: block;
position: absolute;
top: 10px;
right: 10px;
font-size: 25px;
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%
);
}
#ez-toc-container .ez-toc-resize-handle {
position: fixed;
transform: translate(50%, 50%);
bottom: 10px !important;
right: 10px !important;
}
/* 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:
/* --- Überschrift mit Zeilenumbruch --- */
@media (min-width: 700px) {
.lange-ue .nowrap {
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 eine responsive Website erstellt wird, 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 wird sichergestellt, 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.
Und hier das dazugehörige HTML:
<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.
- 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.
Der Beitrag wurde mit fachlicher Unterstützung erstellt.
Aktualisiert im Jahr 2024 Oktober