Anklicken eines Ankerlinks, dann sanftes Scrollen zur Scrollposition, ggf. mit Offset. Im Idealfall sollte dies sowohl innerhalb einer Seite als auch über mehrere Seiten hinweg funktionieren.
Die css Anweisungen:
1 2 3 4 |
html { scroll-behavior: smooth; scroll-padding: 100px; } |
nutzen und gut ist. Oder?
Leider ist das nicht so einfach.
Eine Smooth-Scroll-Funktion zu einem Anker mit Offset, die sowohl seitenintern als auch seitenübergreifend funktioniert, ist nicht so einfach zu realisieren, wie es auf den ersten Blick scheinen mag, auch wenn manche Youtube-Tutorials dies suggerieren.
Einige Browser verhalten sich nicht in allen Situationen wie erwartet. Beispielsweise funktioniert der obige Code bei seitenübergreifenden Ankerlinks im Firefox derzeit nicht. Firefox ignoriert die Anweisung smooth.
Wird der Seitensprung selbst mit Javascript programmiert, treten weitere Probleme auf. Zum einen kann das Standardverhalten des Browsers, der den Ankerlink ausführt, bevor die eigenen Funktionen greifen, einen Strich durch die Rechnung machen. Zum anderen können Animationseffekte von Elementen auf der Zielseite die Berechnung der Ankerposition verfälschen.
Ein kurzes Googeln ergibt zwar unzählige Lösungen zur Implementierung von Smooth Scroll, die auf den ersten Blick auch funktionieren, aber bei den meisten habe ich im Laufe der Zeit immer wieder Probleme der oben genannten Art festgestellt.
Meine Scroll-Lösung sieht nun so aus. Einige Funktionen, wie z.B. die kurze Zeitverzögerung, erscheinen auf den ersten Blick unnötig, sind aber in der Praxis notwendig.
Anwendung:
Anker in Seiten definieren, die mit der Zeichenfolge „scroll“ beginnen, also z.B. so:
1 |
id="scrollPosition01" |
1 |
<a name="scrollPosition02">Position02</a> |
Ankerlinks setzen z.B. so:
1 |
<a href="index.html#scrollPosition01">Klicke hier um zu Position01 zu gelangen</a> |
Oder wenn seitenübergreifend nicht notwendig:
1 |
<a href="#scrollPosition02">Klicke hier um zu Position02 zu gelangen</a> |
Javascript einbinden:
Den folgenden Javascript Code in die Seite oder in das Projekt entsprechend einbinden. Die Variable offset wie gewünscht setzen. Zum Beispiel bedeutet -92, dass die Ankerposition gleich Ankerposition -92 ist, was 92 Pixel über der Ankerposition entspricht. Der Offset kann natürlich auch auf 0 gesetzt werden, sodass exakt zur Ankerposition gescolllt wird. Der Offset kann auch auf positive Werte gesetzt werden, sodass unterhalb der Ankerposition gessrollt wird.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
(function() { const OFFSET = -5; // Offset for smooth scrolling // Smoothly scroll to the target element with an offset function scrollToAnchor(target) { if (target) { window.scrollTo({ top: target.getBoundingClientRect().top + window.scrollY + OFFSET, behavior: 'smooth' }); } } // Perform the smooth scrolling based on hash function performScroll(targetHash) { const target = document.querySelector(targetHash) || document.getElementsByName(targetHash.slice(1))[0]; if (target) { setTimeout(() => { scrollToAnchor(target); history.replaceState(null, null, targetHash); // Update URL hash after scrolling }, 10); } } // Initialize scroll handling based on URL or session storage function initializeScroll() { const targetHash = sessionStorage.getItem('scrollTarget') || window.location.hash; if (targetHash.startsWith('#scroll')) { sessionStorage.removeItem('scrollTarget'); // Clean up session storage performScroll(targetHash); } } // Handle page load events function onPageLoad() { initializeScroll(); } // Handle hash change events function onHashChange() { performScroll(window.location.hash); } // Handle anchor link clicks function onAnchorLinkClick(event) { const currentUrl = window.location.href.split('#')[0]; // Current page URL without hash const anchorUrl = this.href.split('#')[0]; // Anchor URL without hash if (currentUrl === anchorUrl) { // In-page navigation const target = document.querySelector(this.hash) || document.getElementsByName(this.hash.slice(1))[0]; if (target) { event.preventDefault(); history.replaceState(null, null, ' '); // Remove hash to prevent jump setTimeout(() => { scrollToAnchor(target); history.replaceState(null, null, this.hash); // Add hash back }, 10); } } else { // Cross-page navigation event.preventDefault(); // Prevent default behavior sessionStorage.setItem('scrollTarget', this.hash); // Store target hash window.location.href = anchorUrl; // Navigate to the target page without hash } } // Handle direct URL entry with hash function onDOMContentLoaded() { if (window.location.hash.startsWith('#scroll')) { sessionStorage.setItem('scrollTarget', window.location.hash); // Store hash for smooth scrolling history.replaceState(null, null, ' '); // Remove hash to prevent default behavior initializeScroll(); // Handle the scroll } } // Initialize event listeners function initializeEventListeners() { window.addEventListener('load', onPageLoad); window.addEventListener('hashchange', onHashChange); window.addEventListener('DOMContentLoaded', onDOMContentLoaded); document.querySelectorAll('a[href*="#scroll"]').forEach(anchor => { anchor.addEventListener('click', onAnchorLinkClick); }); } // Start the script initializeEventListeners(); })(); |
Viel Spaß beim Einbau.