JavaScript Scrolling
Scroll-Events in JavaScript ermöglichen Entwicklern, auf das Scrollen einer Webseite zu reagieren – nützlich für Lazy Loading und mehr.
JavaScript Scroll-Events und Scroll-Techniken verstehen
Scroll-Events in JavaScript ermöglichen es Ihnen, auf die Position des Benutzers auf einer Seite zu reagieren. Sie bilden die Grundlage für Funktionen wie Parallax-Effekte, das Auslösen von Animationen basierend auf der Scroll-Position, Infinite Scroll, „Zurück nach oben"-Buttons, fixierte Header und Lesefortschrittsbalken. Dieser Leitfaden erklärt, wie man die aktuelle Scroll-Position ausliest, wie man programmgesteuert scrollt, wie man das scroll-Event effizient verwaltet und wann der moderne IntersectionObserver die bessere Wahl ist.
Die aktuelle Scroll-Position auslesen
Bevor Sie auf Scrollen reagieren können, müssen Sie in der Regel wissen, wie weit die Seite gescrollt wurde. Die zuverlässigsten Eigenschaften befinden sich am window-Objekt:
window.scrollY— vertikale Scroll-Distanz in Pixeln (auchwindow.pageYOffset, ein älterer Alias).window.scrollX— horizontale Scroll-Distanz in Pixeln (Aliaswindow.pageXOffset).
Für ein einzelnes scrollbares Element verwenden Sie stattdessen element.scrollTop und element.scrollLeft. Diese sind les- und schreibbar: Weist man ihnen einen Wert zu, springt das Element direkt zu dieser Position.
// How far down the whole page has the user scrolled?
console.log(window.scrollY); // e.g. 0 at the top, 420 partway down
// Total scrollable height of the document
const docHeight = document.documentElement.scrollHeight;
const winHeight = window.innerHeight;
// How close to the bottom are we (0 = top, 1 = bottom)?
const progress = window.scrollY / (docHeight - winHeight);
console.log(progress);Für elementbezogene Abstände und einen genaueren Blick auf getBoundingClientRect siehe JavaScript Koordinaten und Fenstergrößen und Scrollen.
Programmgesteuert scrollen
Sie hören nicht nur auf Scroll-Events — Sie können Scrollen auch auslösen. Diese Methoden akzeptieren eine behavior: 'smooth'-Option für einen animierten Übergang statt eines sofortigen Sprungs:
window.scrollTo(x, y)— scrollt zu einer absoluten Position.window.scrollBy(dx, dy)— scrollt um einen relativen Betrag von der aktuellen Position.element.scrollIntoView(options)— scrollt, sodass ein bestimmtes Element sichtbar wird.
// Jump to the very top, smoothly
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
// Nudge down by one viewport height
window.scrollBy({ top: window.innerHeight, behavior: 'smooth' });
// Bring an element into view (e.g. after navigating to an anchor)
document.querySelector('#section-2')
.scrollIntoView({ behavior: 'smooth', block: 'start' });Dies ist der richtige Weg, um einen „Zurück nach oben"-Button oder eine sanfte seitenintere Ankernavigation zu implementieren. Verwenden Sie querySelector, um das Zielelement zuerst zu greifen.
Das JavaScript Scroll-Event
Das scroll-Event wird ausgelöst, wenn die Dokumentansicht oder ein scrollbares Element gescrollt wird. Es ist eines der am häufigsten verwendeten Events für dynamische, interaktive Designs.
Grundlegende Konzepte
- Event-Häufigkeit: Das
scroll-Event kann dutzende Male pro Sekunde ausgelöst werden, daher läuft sein Handler sehr oft. Aufwändige Arbeit (Layout-Lesevorgänge, DOM-Schreibvorgänge, Netzwerkanfragen) bei jedem Auslösen führt zu ruckeligem Scrollen. Die Standardlösung ist das Throttling oder Debouncing des Handlers. windowvs. Element-Scrollen: Sie können auf Scroll-Events am gesamten Fenster (window.addEventListener('scroll', ...)) oder an einem bestimmten overflow-scrollbaren Element (el.addEventListener('scroll', ...)) horchen.scrollbubbled nicht: Einscroll-Event an einem Element wird nicht zum Dokument hochgeleitet. Hängen Sie den Listener daher an das Element, das tatsächlich scrollt.
Throttle vs. Debounce
Beide begrenzen, wie oft Ihr Handler ausgeführt wird, verhalten sich aber unterschiedlich:
- Debounce wartet, bis das Scrollen für
waitMillisekunden aufgehört hat, und führt den Handler dann einmal aus. Geeignet für „tue etwas, wenn der Benutzer aufgehört hat zu scrollen" (z. B. Scroll-Position speichern). - Throttle führt den Handler während des Scrollens höchstens einmal alle
waitMillisekunden aus. Besser für kontinuierliche Effekte wie Fortschrittsbalken, bei denen regelmäßige Updates während des Scrollens gewünscht sind.
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
function throttle(func, wait) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= wait) {
last = now;
func.apply(this, args);
}
};
}
// Debounce: runs once 100ms after scrolling stops
window.addEventListener('scroll', debounce(() => {
// handle scroll logic here
}, 100));
// Throttle: runs at most every 100ms while scrolling
window.addEventListener('scroll', throttle(() => {
// update a progress bar, etc.
}, 100));Beide setTimeout-basierten Hilfsfunktionen bauen auf den Scheduling-APIs von setTimeout / setInterval auf.
Praktische Beispiele zur Scroll-Event-Behandlung
Beispiel 1: Navigation beim Scrollen ein-/ausblenden
Dieses Beispiel zeigt, wie man eine Navigationsleiste beim Herunterscrollen ausblendet und beim Hochscrollen wieder einblendet – ein verbreitetes Muster auf modernen Websites, um den verfügbaren Bildschirmbereich zu maximieren.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Scroll Event Navigation Example</title>
<style>
#navbar {
position: fixed;
top: 0;
width: 100%;
background-color: #333;
color: white;
text-align: center;
padding: 10px;
transition: top 0.3s;
}
body {
padding: 0;
margin: 0;
height: 1500px; /* to ensure scrolling */
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<p style="display: flex; justify-content: center; align-items: center; margin-top: 50vh;"><strong>When you scroll down, the navigation bar disappears. Scroll back up, and it reappears!</strong></p>
<div id="navbar">Navigation Bar</div>
<script>
let lastScrollTop = 0;
window.addEventListener(
"scroll",
function () {
let currentScroll = window.pageYOffset || document.documentElement.scrollTop;
if (currentScroll > lastScrollTop) {
document.getElementById("navbar").style.top = "-50px"; // Adjust based on nav height
} else {
document.getElementById("navbar").style.top = "0px";
}
lastScrollTop = currentScroll <= 0 ? 0 : currentScroll; // For Mobile or negative scrolling
},
false
);
</script>
</body>
</html>Erklärung:
- Das Skript verfolgt die letzte Scroll-Position und vergleicht sie mit der aktuellen. Ist die aktuelle Position größer, scrollt der Benutzer nach unten, und die Navigationsleiste wird durch Anpassen ihrer
top-Position nach außerhalb des Bildschirms ausgeblendet. - Beim Hochscrollen erscheint die Navigationsleiste wieder.
Beispiel 2: Scroll-Animations-Auslöser
Dieses Beispiel zeigt, wie Animationen ausgelöst werden können, wenn Elemente beim Scrollen in den viewport eintreten.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Scroll Animation Trigger</title>
<style>
.box {
width: 100px;
height: 100px;
background: red;
opacity: 0;
transition: opacity 2s;
margin: 600px auto; /* Ensures it starts out of view */
}
</style>
</head>
<body>
<p>Keep scrolling down to see the animation!</p>
<div class="box"></div>
<script>
let hasAnimated = false;
window.addEventListener('scroll', function() {
const box = document.querySelector('.box');
const rect = box.getBoundingClientRect();
if (rect.top < window.innerHeight && !hasAnimated) {
box.style.opacity = 1; // Fade in the box when it comes into view
hasAnimated = true;
}
});
</script>
</body>
</html>Erklärung:
- Sichtbarkeitsprüfung: Das Skript prüft, ob die Oberkante des
.box-Elements sich innerhalb des viewport befindet, und setzt dessen Deckkraft auf 1, wodurch ein Einblendeffekt ausgelöst wird. Ein Flag verhindert, dass die Animation bei nachfolgenden Scroll-Events erneut ausgelöst wird.
Beispiel 3: Parallax-Scrolling-Effekt
Dieses Beispiel zeigt einen einfachen Parallax-Effekt, bei dem sich das Hintergrundbild beim Herunterscrollen mit einer anderen Geschwindigkeit bewegt als der Vordergrundinhalt.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Enhanced Parallax Scrolling</title>
<style>
body, html {
height: 100%;
margin: 0;
font-family: Arial, sans-serif;
overflow-x: hidden; /* Prevent horizontal scroll */
}
.parallax {
height: 100vh; /* Full height of the viewport */
position: relative;
background: url('https://via.placeholder.com/1920x1080') no-repeat center center;
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 36px;
letter-spacing: 1px;
}
.content {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: white;
color: #333;
font-size: 24px;
padding: 0 20px;
text-align: center;
box-sizing: border-box;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="content">Scroll down to see the parallax effect!</div>
<div class="parallax">Stunning Parallax!</div>
<div class="content">Keep scrolling to see more effects.</div>
<div class="parallax"></div>
<div class="content">You have reached the end. Amazing, right?</div>
<script>
document.addEventListener('scroll', function() {
document.querySelectorAll('.parallax').forEach(function(el) {
const factor = 0.5; // Change this for more or less parallax
const offset = window.pageYOffset * factor - 300; // Adjusts the starting position of background
el.style.backgroundPositionY = offset + 'px';
});
});
</script>
</body>
</html>Erklärung:
- CSS-Stile: Die
.parallax-Klasse legt fest, dass das Hintergrundbild den Container ausfüllt und zentriert wird. Das Beispiel verlässt sich vollständig auf JavaScript für die Positionierung und vermeidetbackground-attachment: fixedin CSS, das auf mobilen Geräten zu Leistungsproblemen führen kann. - JavaScript-Funktionalität: Beim Scrollen berechnet das Skript eine neue vertikale Position für das Hintergrundbild aus dem Scroll-Offset. Durch dynamisches Anpassen von
backgroundPositionYverschiebt sich das Bild mit einer anderen Rate als der Seiteninhalt, was den Parallax-Tiefeneffekt erzeugt.
Zusammenfassend bewegen sich die Hintergrundbilder beim Scrollen langsamer als der Text, sodass sie in einer anderen Tiefenebene zu liegen scheinen.
Die moderne Alternative: IntersectionObserver
Für den häufigen Anwendungsfall „tue etwas, wenn ein Element sichtbar wird" (Lazy Loading, Einblendanimationen, Infinite Scroll) ist IntersectionObserver der empfohlene moderne Ansatz. Anstatt Ihren Code bei jedem scroll-Event auszuführen und manuell Positionen auszulesen, teilt der Browser Ihnen asynchron mit, wenn ein Element einen Schwellenwert überschreitet — wesentlich effizienter und ruckelfreier.
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('visible'); // run once it enters view
observer.unobserve(entry.target); // stop watching it
}
});
},
{ threshold: 0.25 } // fire when 25% of the element is visible
);
document.querySelectorAll('.box').forEach((el) => observer.observe(el));Verwenden Sie das scroll-Event, wenn Sie eine kontinuierliche Auswertung der Scroll-Position benötigen (Parallax, Fortschrittsbalken). Verwenden Sie IntersectionObserver, wenn Sie nur wissen möchten, ob ein Element in den viewport eingetreten oder aus ihm ausgetreten ist. Es ähnelt konzeptionell der MutationObserver-API.
Scrollen sperren und wiederherstellen
Eine häufige UI-Anforderung ist das Sperren des Seiten-Scrollens, während ein Modal oder Menü geöffnet ist. Das scroll-Event lässt sich nicht zuverlässig mit preventDefault() abbrechen (es wird ausgelöst, nachdem das Scrollen bereits stattgefunden hat). Verwenden Sie stattdessen die CSS-Eigenschaft overflow:
// Lock scrolling (e.g. when opening a modal)
document.body.style.overflow = 'hidden';
// Restore it when the modal closes
document.body.style.overflow = '';Fazit
Der effektive Umgang mit Scroll-Events ist eine wichtige Fähigkeit für Webentwickler und ermöglicht interaktivere und performantere Websites. Ob Sie UI-Verbesserungen wie dynamische Navigationsleisten implementieren oder einen Parallax-Effekt auf Ihrer Seite einsetzen – das Verständnis und die korrekte Handhabung von Scrollen in JavaScript kann die Benutzererfahrung erheblich verbessern.