Intersectionosservatori ti consente di sapere quando un elemento osservato entra o esce dall'area visibile del browser.
Supponiamo di voler monitorare quando un elemento del DOM entra nell'area visibile visibile. Ciò può essere utile per eseguire il caricamento lento delle immagini in tempo o per sapere se l'utente sta effettivamente guardando un determinato banner pubblicitario. Puoi farlo collegando l'evento di scorrimento o utilizzando un timer periodico e chiamando getBoundingClientRect()
.
su quell'elemento.
Tuttavia, questo approccio risulta estremamente lento poiché ogni chiamata a getBoundingClientRect()
obbliga il browser a ridefinire il layout dell'intera pagina e introdurrà una notevole capacità di jank per il tuo sito web. Le pratiche diventano impossibili se sai che il tuo sito viene caricato all'interno di un iframe e vuoi sapere quando l'utente può visualizzare un elemento. Il modello a origine singola e il browser non ti permettono di accedere ai dati della pagina web che contiene l'iframe. Questo è un problema comune per gli annunci, ad esempio, che vengono caricati spesso tramite iframe.
Per rendere più efficiente questo test di visibilità, IntersectionObserver
è stato progettato ed è disponibile in tutti i browser moderni. IntersectionObserver
ti informa quando un elemento osservato entra o esce dall'area visibile del browser.
Come creare un IntersectionObserver
L'API è piuttosto piccola e viene descritta meglio utilizzando un esempio:
const io = new IntersectionObserver(entries => {
console.log(entries);
}, {
/* Using default options. Details below */
});
// Start observing an element
io.observe(element);
// Stop observing an element
// io.unobserve(element);
// Disable entire IntersectionObserver
// io.disconnect();
Se utilizzi le opzioni predefinite per IntersectionObserver
, il callback verrà chiamato sia quando l'elemento diventa parzialmente visibile sia quando esce completamente dall'area visibile.
Se devi osservare più elementi, è possibile e consigliato osservare più elementi utilizzando la stessa istanza IntersectionObserver
chiamando observe()
più volte.
Un parametro entries
viene passato al callback, ovvero un array di oggetti IntersectionObserverEntry
. Ciascun oggetto di questo tipo contiene dati di intersezione aggiornati per uno degli elementi osservati.
🔽[IntersectionObserverEntry]
time: 3893.92
🔽rootBounds: ClientRect
bottom: 920
height: 1024
left: 0
right: 1024
top: 0
width: 920
🔽boundingClientRect: ClientRect
// ...
🔽intersectionRect: ClientRect
// ...
intersectionRatio: 0.54
🔽target: div#observee
// ...
rootBounds
è il risultato della chiamata a getBoundingClientRect()
sull'elemento principale, che per impostazione predefinita è l'area visibile. boundingClientRect
è il risultato di getBoundingClientRect()
chiamato sull'elemento osservato. intersectionRect
è l'intersezione di questi due rettangoli e ti indica efficacemente quale parte dell'elemento osservato è visibile. intersectionRatio
è strettamente correlato e ti indica quanto è visibile l'elemento. Grazie a queste informazioni, ora puoi implementare funzionalità come il caricamento just-in-time degli asset prima che diventino visibili sullo schermo. in modo efficiente.
IntersectionObserver
pubblicano i dati in modo asincrono e il codice di callback verrà eseguito nel thread principale. Inoltre, le specifiche indicano in realtà che le implementazioni IntersectionObserver
devono utilizzare requestIdleCallback()
. Ciò significa che la chiamata al callback fornito ha una priorità bassa e verrà effettuata dal browser durante il tempo di inattività. Si tratta di una decisione di progettazione consapevole.
div a scorrimento
Lo scorrimento all'interno di un elemento non mi piace molto, ma non sono qui per giudicare e nemmeno IntersectionObserver
. L'oggetto options
utilizza un'opzione root
che consente di definire un'alternativa all'area visibile come principale. È importante tenere presente che root
deve essere un predecessore di tutti gli elementi osservati.
Incrocia tutte le cose!
No! Cattivo sviluppatore! Questo non rappresenta l'utilizzo consapevole dei cicli della CPU dell'utente. Prendiamo come esempio uno scorrimento continuo: in questo scenario, è sicuramente consigliabile aggiungere sentinel al DOM e osservarle (e riciclarle). Dovresti aggiungere una sentinella vicino all'ultimo elemento dello scorrimento infinito. Quando la sentinella viene visualizzata, puoi utilizzare il callback per caricare i dati, creare gli elementi successivi, collegarli al DOM e riposizionare la sentinella di conseguenza. Se ricicli correttamente la sentinella, non sono necessarie ulteriori chiamate a observe()
. Il IntersectionObserver
continua a funzionare.
Altri aggiornamenti, per favore
Come accennato in precedenza, il callback verrà attivato una sola volta quando l'elemento osservato diventa parzialmente visibile e un'altra volta quando ha lasciato l'area visibile. In questo modo IntersectionObserver
dà una risposta alla domanda "L'elemento X è visualizzato?". In alcuni casi d'uso, tuttavia, potrebbe non essere sufficiente.
È qui che entra in gioco l'opzione threshold
. Consente di definire un array di soglie di intersectionRatio
. Il callback verrà chiamato ogni volta che intersectionRatio
incrocia uno di questi valori. Il valore predefinito di threshold
è [0]
e spiega il comportamento predefinito. Se modifichiamo threshold
in [0, 0.25, 0.5, 0.75, 1]
, riceveremo una notifica ogni volta che un ulteriore quarto dell'elemento diventa visibile:
Altre opzioni?
Al momento, esiste una sola opzione aggiuntiva rispetto a quelle elencate sopra. rootMargin
consente di specificare i margini per la radice, in modo da aumentare o ridurre l'area utilizzata per le incroci. Questi margini vengono specificati mediante una stringa in stile CSS, ovvero la "10px 20px 30px 40px"
, che specifica rispettivamente i margini superiore, destro, inferiore e sinistro. In sintesi, lo struct IntersectionObserver
offre le seguenti opzioni:
new IntersectionObserver(entries => {/* … */}, {
// The root to use for intersection.
// If not provided, use the top-level document's viewport.
root: null,
// Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
// If an explicit root element is specified, components may be percentages of the
// root element size. If no explicit root element is specified, using a
// percentage is an error.
rootMargin: "0px",
// Threshold(s) at which to trigger callback, specified as a ratio, or list of
// ratios, of (visible area / total area) of the observed element (hence all
// entries must be in the range [0, 1]). Callback will be invoked when the
// visible ratio of the observed element crosses a threshold in the list.
threshold: [0],
});
<iframe>
magico
I IntersectionObserver
sono stati progettati in modo specifico per i servizi pubblicitari e i widget dei social network, che utilizzano spesso elementi <iframe>
e potrebbero trarre vantaggio dal sapere se sono visibili. Se un <iframe>
osserva uno dei suoi elementi, sia lo scorrimento del <iframe>
sia lo scorrimento della finestra contenente il <iframe>
attiveranno il callback nei momenti appropriati. In quest'ultimo caso, tuttavia, il criterio rootBounds
verrà impostato su null
per evitare la fuga di dati tra le origini.
Quali sono gli argomenti non di IntersectionObserver
?
Tieni presente che IntersectionObserver
non è intenzionalmente né perfetto per pixel né a bassa latenza. Il loro utilizzo per implementare attività come le animazioni dipendenti dallo scorrimento non riuscirà, perché i dati, in definitiva, non saranno aggiornati quando li utilizzerai. L'spiegatore contiene ulteriori dettagli sui casi d'uso originali di IntersectionObserver
.
Quanto posso fare durante la richiamata?
Short 'n Sweet: trascorrere troppo tempo nella richiamata comporterà un ritardo nella tua app; si applicano tutte le prassi comuni.
Vai avanti e interseca i tuoi elementi
Il supporto browser per IntersectionObserver
è buono, poiché è disponibile in tutti i browser moderni. Se necessario, nei browser meno recenti è possibile utilizzare un polyfill, disponibile nel repository di WiCG. Ovviamente, il polyfill non ti consente di ottenere i vantaggi in termini di prestazioni offerti da un'implementazione nativa.
Puoi iniziare subito a utilizzare IntersectionObserver
. Raccontaci cosa hai trovato.