La sincronizzazione dello stato della UI con la posizione di aggancio di un container scorrevole richiedeva tradizionalmente listener di eventi di scorrimento complessi, calcoli manuali degli offset di scorrimento e osservatori di intersezione. L'evento scrollsnapchange fornisce un modo nativo ed efficiente per rilevare quando uno scroller si è stabilizzato su un nuovo target di aggancio, il che lo rende utile per sincronizzare le barre laterali o evidenziare la sezione attiva in un sommario.
Implementazione
1. Configura l'allineamento dello scorrimento in CSS
Il container deve avere scroll-snap-type definito e avere elementi secondari con scroll-snap-align affinché il browser possa monitorare i target di aggancio. In un articolo lungo con un sommario, puoi utilizzare questo attributo per agganciare le intestazioni delle sezioni alla parte superiore dell'area visibile.
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. Ascolta le modifiche di Snap
Utilizza l'evento scrollsnapchange sul contenitore di scorrimento per reagire quando l'utente termina lo scorrimento e il browser si aggancia a un nuovo elemento. Nella nostra demo del sommario, utilizziamo questa funzionalità per evidenziare il link attivo nella barra laterale.
<!-- 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);
}
});
Accessibilità
Per un sommario, assicurati che i link della barra laterale utilizzino aria-current="true" o aria-current="location" quando sono attivi.
Inoltre, fai attenzione quando utilizzi il valore mandatory per scroll-snap-type, in quanto può rendere inaccessibili i contenuti tra i punti di aggancio quando sono più lunghi dello schermo.
Strategie di riserva
Se scrollsnapchange non è supportato, utilizza IntersectionObserver per rilevare quale elemento si trova attualmente nella parte superiore dello scroller. Tieni presente che questo comportamento è diverso da scrollsnapchange, in quanto l'attivazione avviene durante lo scorrimento, anziché solo quando lo scorrimento è terminato.
// 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));
}