Die Synchronisierung des UI-Status mit der Einrastposition eines scrollbaren Containers erforderte bisher komplexe Scroll-Event-Listener, manuelle Berechnungen von Scroll-Offsets und Intersection Observer. Das Ereignis scrollsnapchange bietet eine native, effiziente Möglichkeit, zu erkennen, wann ein Scroller auf einem neuen Einrastziel gelandet ist. Das ist nützlich, um Seitenleisten zu synchronisieren oder den aktiven Abschnitt in einem Inhaltsverzeichnis hervorzuheben.
Implementierung
1. Scroll Snap in CSS konfigurieren
Für den Container muss scroll-snap-type definiert sein und er muss untergeordnete Elemente mit scroll-snap-align haben, damit der Browser die Einrastziele verfolgen kann. In einem langen Artikel mit einem Inhaltsverzeichnis können Sie damit Abschnittsüberschriften am oberen Rand des Darstellungsbereichs fixieren.
main {
/* Enable scroll snapping on the container */
scroll-snap-type: y proximity;
overflow-y: auto;
}
h2 {
/* Define how headers align when snapped */
scroll-snap-align: start;
}
2. Auf Änderungen am Einrasten warten
Verwenden Sie das Ereignis scrollsnapchange für den Scrollcontainer, um zu reagieren, wenn der Nutzer mit dem Scrollen fertig ist und der Browser zu einem neuen Element springt. In unserer Inhaltsverzeichnis-Demo verwenden wir dies, um den aktiven Link in der Seitenleiste hervorzuheben.
<!-- MANDATORY: Wrap table of contents links inside a proper navigation landmark -->
<nav aria-label="Table of contents">
<ul>
<li><a href="#section-1" aria-current="location">Section 1</a></li>
<li><a href="#section-2">Section 2</a></li>
</ul>
</nav>
const main = document.getElementById('main');
const links = document.querySelectorAll('nav a');
// The event fires when the scroller settles on a new snap target
main.addEventListener('scrollsnapchange', (event) => {
// Use snapTargetBlock for vertical or snapTargetInline for horizontal
const snappedHeader = event.snapTargetBlock;
if (snappedHeader) {
setSelectedParagraph(snappedHeader.id);
}
});
Bedienungshilfen
Achten Sie bei einem Inhaltsverzeichnis darauf, dass die Links in der Seitenleiste aria-current="true" oder aria-current="location" verwenden, wenn sie aktiv sind.
Seien Sie außerdem vorsichtig, wenn Sie den Wert mandatory für scroll-snap-type verwenden, da Inhalte zwischen Einrastpunkten unzugänglich werden können, wenn sie länger als der Bildschirm sind.
Fallback-Strategien
Wenn scrollsnapchange nicht unterstützt wird, verwenden Sie IntersectionObserver, um zu ermitteln, welches Element sich gerade oben im Scroller befindet. Beachten Sie, dass sich dieses Verhalten von scrollsnapchange unterscheidet, da es während des Scrollens ausgelöst wird und nicht erst, wenn das Scrollen beendet ist.
// Feature detect support for scroll snap events
if (!('onscrollsnapchange' in HTMLElement.prototype)) {
const observer = new IntersectionObserver(
() => {
// Each time the set of intersecting headers changes, find the top
// header that is visible.
const topEntry = [...headers].reduce((currentTop, header) => {
// Use the bottom to handle scrolling up, when the top is still offscreen
const {bottom} = header.getBoundingClientRect();
// Don't match if the header's bottom is above the scrollport
if (bottom < 0) return;
if (!currentTop) return header;
return bottom <
currentTop.getBoundingClientRect().bottom
? header
: currentTop;
}, undefined);
if (topEntry) setSelectedParagraph(topEntry.id);
},
{ root: main, threshold: 0.9 // Adjust based on your use case },
);
// Observe all snap targets (e.g., section headers)
document.querySelectorAll('h2').forEach(header => observer.observe(header));
}