Scrollspy
In Bootstrap v6.0.0 neu aufgebaut
Navigation, List Group oder einfache Links markieren automatisch den Abschnitt, der gerade im sichtbaren Bereich liegt.
Scrollspy setzt die Klasse .active an Links (<a>), sobald das Element mit der passenden id aus dem href ins Bild scrollt. Am besten funktioniert das mit einer Nav oder List Group, aber auch beliebige Anker auf der Seite werden unterstützt.
- Zwei Zutaten: eine Navigation (oder Links) und ein scrollbarer Container – entweder
<body>oder ein Element mit festerheightundoverflow-y: scroll. - Aktivieren: Am Container
data-bs-spy="scroll"unddata-bs-target="#navId"setzen. Enthält er nichts Fokussierbares, zusätzlichtabindex="0"für Tastaturzugriff. - Ziele müssen existieren:
<a href="#home">braucht ein passendes Element wie<div id="home">, sonst wird der Link ignoriert. - Unsichtbare Ziele werden übersprungen (siehe Nicht sichtbare Elemente).
- Sonderzeichen in IDs: Ziele werden per
getElementByIdgesucht, daher funktionieren auch IDs wie#item.1,#section:overviewoder#%2Fpath.
Quelle: Bootstrap-Dokumentation (englisch), übersetzt und bearbeitet. Doku lizenziert unter CC BY 3.0.
Erkennung
Scrollspy verfolgt die Abschnitte mit einem IntersectionObserver statt die Scrollposition laufend abzufragen. Maßgeblich ist allein eine Aktivierungslinie nahe der Oberkante des Scroll-Containers – das Verhalten ist dadurch vorhersehbar.
- Aktiv ist der tiefste Abschnitt, dessen Oberkante die Aktivierungslinie bereits überschritten hat – also der, den du gerade liest.
- Zwischen zwei Überschriften bleibt der zuletzt aktivierte Abschnitt aktiv, bis der nächste die Linie kreuzt.
- Ganz oben, bevor ein Abschnitt die Linie erreicht, ist der erste Abschnitt aktiv.
- Ganz unten wird der letzte Abschnitt aktiviert, auch wenn seine Oberkante die Linie nie erreicht – praktisch bei kurzen Schlussabschnitten.
Die Lage der Linie legst du mit topMargin fest (Prozent oder Pixel ab Oberkante, z. B. 96px unter einer Sticky-Navbar). Volle Kontrolle bietet der rohe IntersectionObserver-String rootMargin. Details unter Optionen.
Beispiele
Hinweis: Der Scroll-Container braucht eine feste Höhe und overflow. In der Originaldoku liefert das die Doku-eigene Klasse .scrollspy-example; hier ist es per Inline-Style style="height:200px;overflow:auto;position:relative;" ergänzt.
Navbar
Scrolle den Bereich unter der Navbar und beobachte, wie die aktive Klasse wechselt. Auch die Einträge im aufgeklappten Menü werden hervorgehoben.
Erste Überschrift
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Zweite Überschrift
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Dritte Überschrift
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Vierte Überschrift
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Fünfte Überschrift
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
<nav id="navbar-example2" class="navbar bg-1 px-3 mb-3 rounded-2">
<a class="navbar-brand" href="#">Navbar</a>
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link" href="#scrollspyHeading1">Erster</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#scrollspyHeading2">Zweiter</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" role="button" data-bs-toggle="menu" aria-expanded="false">Menü</a>
<div class="menu">
<a class="menu-item" href="#scrollspyHeading3">Dritter</a>
<a class="menu-item" href="#scrollspyHeading4">Vierter</a>
<hr class="menu-divider">
<a class="menu-item" href="#scrollspyHeading5">Fünfter</a>
</div>
</li>
</ul>
</nav>
<div class="scrollspy-example bg-1 p-3 rounded-2" data-bs-spy="scroll" data-bs-target="#navbar-example2" data-bs-root-margin="0px 0px -40%" data-bs-smooth-scroll="true" tabindex="0" style="height:200px;overflow:auto;position:relative;">
<h4 id="scrollspyHeading1">Erste Überschrift</h4>
<p>...</p>
<h4 id="scrollspyHeading2">Zweite Überschrift</h4>
<p>...</p>
<h4 id="scrollspyHeading3">Dritte Überschrift</h4>
<p>...</p>
<h4 id="scrollspyHeading4">Vierte Überschrift</h4>
<p>...</p>
<h4 id="scrollspyHeading5">Fünfte Überschrift</h4>
<p>...</p>
</div>Verschachtelte Nav
Scrollspy funktioniert auch mit verschachtelten .navs. Ist ein untergeordneter Eintrag aktiv, werden auch seine Eltern als aktiv markiert.
Eintrag 1
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
Eintrag 1-1
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
Eintrag 1-2
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
Eintrag 2
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
Eintrag 3
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
Eintrag 3-1
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
Eintrag 3-2
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Das JavaScript-Plugin versucht, unter allen sichtbaren Elementen das richtige auszuwählen. Mehrere gleichzeitig sichtbare Scrollspy-Ziele können zu Problemen führen.
<div class="row">
<div class="col-4">
<nav id="navbar-example3" class="h-100 flex-column align-items-stretch pe-4 border-end">
<nav class="nav nav-pills flex-column">
<a class="nav-link" href="#item-1">Eintrag 1</a>
<nav class="nav nav-pills flex-column">
<a class="nav-link ms-3 my-1" href="#item-1-1">Eintrag 1-1</a>
<a class="nav-link ms-3 my-1" href="#item-1-2">Eintrag 1-2</a>
</nav>
<a class="nav-link" href="#item-2">Eintrag 2</a>
<a class="nav-link" href="#item-3">Eintrag 3</a>
<nav class="nav nav-pills flex-column">
<a class="nav-link ms-3 my-1" href="#item-3-1">Eintrag 3-1</a>
<a class="nav-link ms-3 my-1" href="#item-3-2">Eintrag 3-2</a>
</nav>
</nav>
</nav>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#navbar-example3" data-bs-smooth-scroll="true" class="scrollspy-example-2" tabindex="0" style="height:200px;overflow:auto;position:relative;">
<div id="item-1">
<h4>Eintrag 1</h4>
<p>...</p>
</div>
<div id="item-1-1">
<h5>Eintrag 1-1</h5>
<p>...</p>
</div>
<div id="item-1-2">
<h5>Eintrag 1-2</h5>
<p>...</p>
</div>
<div id="item-2">
<h4>Eintrag 2</h4>
<p>...</p>
</div>
<div id="item-3">
<h4>Eintrag 3</h4>
<p>...</p>
</div>
<div id="item-3-1">
<h5>Eintrag 3-1</h5>
<p>...</p>
</div>
<div id="item-3-2">
<h5>Eintrag 3-2</h5>
<p>...</p>
</div>
</div>
</div>
</div>List Group
Auch mit .list-group klappt es. Scrolle den Bereich neben der Liste und beobachte den Wechsel der aktiven Klasse.
Eintrag 1
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 2
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 3
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 4
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
<div class="row">
<div class="col-4">
<div id="list-example" class="list-group">
<a class="list-group-item list-group-item-action" href="#list-item-1">Eintrag 1</a>
<a class="list-group-item list-group-item-action" href="#list-item-2">Eintrag 2</a>
<a class="list-group-item list-group-item-action" href="#list-item-3">Eintrag 3</a>
<a class="list-group-item list-group-item-action" href="#list-item-4">Eintrag 4</a>
</div>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#list-example" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0" style="height:200px;overflow:auto;position:relative;">
<h4 id="list-item-1">Eintrag 1</h4>
<p>...</p>
<h4 id="list-item-2">Eintrag 2</h4>
<p>...</p>
<h4 id="list-item-3">Eintrag 3</h4>
<p>...</p>
<h4 id="list-item-4">Eintrag 4</h4>
<p>...</p>
</div>
</div>
</div>Einfache Anker
Scrollspy ist nicht auf Navs und List Groups beschränkt, sondern funktioniert mit allen <a>-Ankern im Dokument.
Eintrag 1
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 2
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 3
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 4
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
Eintrag 5
Dies ist Platzhaltertext für die Scrollspy-Seite. Beim Scrollen wird jeweils der passende Navigationslink hervorgehoben. Der Text wiederholt sich im gesamten Beispiel, damit genug Inhalt zum Scrollen und Hervorheben vorhanden ist.
<div class="row">
<div class="col-4">
<div id="simple-list-example" class="d-flex flex-column gap-2 simple-list-example-scrollspy text-center">
<a class="p-1 rounded" href="#simple-list-item-1">Eintrag 1</a>
<a class="p-1 rounded" href="#simple-list-item-2">Eintrag 2</a>
<a class="p-1 rounded" href="#simple-list-item-3">Eintrag 3</a>
<a class="p-1 rounded" href="#simple-list-item-4">Eintrag 4</a>
<a class="p-1 rounded" href="#simple-list-item-5">Eintrag 5</a>
</div>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#simple-list-example" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0" style="height:200px;overflow:auto;position:relative;">
<h4 id="simple-list-item-1">Eintrag 1</h4>
<p>...</p>
<h4 id="simple-list-item-2">Eintrag 2</h4>
<p>...</p>
<h4 id="simple-list-item-3">Eintrag 3</h4>
<p>...</p>
<h4 id="simple-list-item-4">Eintrag 4</h4>
<p>...</p>
<h4 id="simple-list-item-5">Eintrag 5</h4>
<p>...</p>
</div>
</div>
</div>Debug-Overlay
Wo genau Scrollspy einen Abschnitt als aktiv einstuft, ist nicht immer leicht vorstellbar. Die Originaldoku nutzt Scrollspy für ihr Inhaltsverzeichnis und bietet dort ein zuschaltbares Debug-Overlay mit roten Hilfslinien:
- Die rot gestrichelte Linie oben ist die Aktivierungslinie. Ein Abschnitt wird aktiv, sobald seine Überschrift darüber scrollt. In der Doku liegt sie bei
96px, knapp unter der Navbar. - Die rote Zone unten leuchtet am Seitenende auf. Dort bleibt der letzte Abschnitt aktiv, auch wenn seine Überschrift die Linie nie erreicht.
Die Hilfslinien werden mit derselben topMargin/rootMargin-Berechnung erzeugt wie im Plugin (siehe Erkennung). Das Overlay selbst ist ein Werkzeug der Originaldoku und hier nicht eingebunden.
Nicht sichtbare Elemente
Unsichtbare Ziel-Elemente werden ignoriert, ihre Nav-Einträge erhalten also kein .active. Wird Scrollspy in einem unsichtbaren Wrapper initialisiert, ignoriert es alle Ziele. Rufe daher refresh auf, sobald der Wrapper sichtbar wird – etwa beim Wechsel eines Tabs:
document.querySelectorAll('#nav-tab>[data-bs-toggle="tab"]').forEach(el => {
el.addEventListener('shown.bs.tab', () => {
const target = el.getAttribute('data-bs-target')
const scrollElem = document.querySelector(`${target} [data-bs-spy="scroll"]`)
bootstrap.ScrollSpy.getOrCreateInstance(scrollElem).refresh()
})
})Verwendung
Per Data-Attribute
Setze data-bs-spy="scroll" an das zu beobachtende Element – meist <body> – und ergänze data-bs-target mit der id oder Klasse des Elternelements deiner .nav.
| Attribut | Beschreibung |
|---|---|
data-bs-spy="scroll" | Aktiviert Scrollspy am scrollbaren Element (oft <body>). |
data-bs-target | CSS-Selektor der Nav, deren Links zu den Abschnitten passen. |
<body data-bs-spy="scroll" data-bs-target="#navbar-example">
...
<div id="navbar-example">
<ul class="nav nav-tabs" role="tablist">
...
</ul>
</div>
...
</body>Per JavaScript
const scrollSpy = new bootstrap.ScrollSpy(document.body, {
target: '#navbar-example'
})Optionen
Optionen lassen sich per Data-Attribut oder JavaScript übergeben.
| Name | Typ | Standard | Beschreibung |
|---|---|---|---|
rootMargin | string, null | null | Erweiterte Übersteuerung für das rootMargin des IntersectionObservers, z. B. 0px 0px -40%. Hat Vorrang vor topMargin. Bei null wird die Aktivierungslinie aus topMargin berechnet. |
smoothScroll | boolean | false | Sanftes Scrollen beim Klick auf einen Link zu einem beobachteten Abschnitt. Danach werden URL-Hash und Fokus auf den Abschnitt gesetzt. |
target | string, DOM-Element | null | Element, auf das Scrollspy angewendet wird. |
threshold | array | [0] | Gültiger threshold-Wert für den IntersectionObserver. |
topMargin | string | 12% | Lage der Aktivierungslinie ab Oberkante des Scroll-Containers, in Prozent (12%) oder Pixeln (96px, z. B. unter einer Sticky-Navbar). Wird ignoriert, wenn rootMargin gesetzt ist. |
Methoden
| Methode | Beschreibung |
|---|---|
dispose | Entfernt Scrollspy vom Element inklusive gespeicherter Daten. |
getInstance | Statisch – liefert die Scrollspy-Instanz zu einem DOM-Element. |
getOrCreateInstance | Statisch – liefert die Instanz oder erzeugt eine neue, falls noch keine existiert. |
refresh | Nach dem Hinzufügen oder Entfernen von Elementen im DOM aufrufen. |
Beispiel für refresh:
const dataSpyList = document.querySelectorAll('[data-bs-spy="scroll"]')
dataSpyList.forEach(dataSpyEl => {
bootstrap.ScrollSpy.getInstance(dataSpyEl).refresh()
})Events
| Event | Beschreibung |
|---|---|
activate.bs.scrollspy | Wird am Scroll-Element ausgelöst, sobald Scrollspy einen Anker aktiviert. |
const firstScrollSpyEl = document.querySelector('[data-bs-spy="scroll"]')
firstScrollSpyEl.addEventListener('activate.bs.scrollspy', () => {
// do something...
})