W3docs

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 (auch window.pageYOffset, ein älterer Alias).
  • window.scrollX — horizontale Scroll-Distanz in Pixeln (Alias window.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.
  • window vs. 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.
  • scroll bubbled nicht: Ein scroll-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 wait Millisekunden 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 wait Millisekunden 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:

  1. 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 vermeidet background-attachment: fixed in CSS, das auf mobilen Geräten zu Leistungsproblemen führen kann.
  2. JavaScript-Funktionalität: Beim Scrollen berechnet das Skript eine neue vertikale Position für das Hintergrundbild aus dem Scroll-Offset. Durch dynamisches Anpassen von backgroundPositionY verschiebt 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.

Übung

Übung
Welche Einsatzmöglichkeiten des JavaScript Scroll-Events sind in der Webentwicklung sinnvoll?
Welche Einsatzmöglichkeiten des JavaScript Scroll-Events sind in der Webentwicklung sinnvoll?
Was this page helpful?