Intersection Observer 2 aggiunge la possibilità non solo di osservare le intersezioni in sé, ma anche di rilevare se l'elemento in intersezione era visibile al momento dell'intersezione.
Intersection Observer v1 è una di quelle API probabilmente amate da tutti e, ora che anche Safari la supporta, finalmente è utilizzabile universalmente in tutti i browser principali. Per un rapido ripasso dell'API,
consiglio di guardare il
micro-suggerimento superpotenziato di Surma su Intersection
Observer v1, incorporato di seguito.
Puoi anche leggere l'articolo approfondito di Surma.
Intersection Observer v1 è stato utilizzato per una vasta gamma di casi d'uso, come il
caricamento lento di immagini e video,
l'invio di notifiche quando gli elementi raggiungono position: sticky
,
l'attivazione di eventi di analisi,
e molti altri.
Per tutti i dettagli, consulta la documentazione di Intersection Observer su MDN, ma come breve promemoria, ecco come appare l'API Intersection Observer v1 nel caso più semplice:
const onIntersection = (entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
console.log(entry);
}
}
};
const observer = new IntersectionObserver(onIntersection);
observer.observe(document.querySelector('#some-target'));
Quali sono le difficoltà con Intersection Observer v1?
Per essere chiari, Intersection Observer v1 è fantastico, ma non è perfetto. Esistono alcuni casi limite in cui l'API non è sufficiente. Diamo un'occhiata più da vicino.
L'API Intersection Observer 1.0 può indicare quando un elemento viene visualizzato nel viewport della finestra, ma non indica se l'elemento è coperto da altri contenuti della pagina (ovvero quando è occluso) o se la sua visualizzazione è stata modificata da effetti visivi come transform
, opacity
,filter
e così via, che possono effettivamente renderlo invisibile.
Per un elemento nel documento di primo livello, queste informazioni possono essere determinate analizzando il DOM tramite JavaScript, ad esempio tramite DocumentOrShadowRoot.elementFromPoint()
, quindi analizzando più in dettaglio.
Al contrario, non è possibile ottenere le stesse informazioni se l'elemento in questione si trova in un iframe di terze parti.
Perché la visibilità effettiva è così importante?
Purtroppo, internet è un luogo che attira malintenzionati con intenzioni peggiori.
Ad esempio, un publisher poco affidabile che pubblica annunci pay-per-click su un sito di contenuti potrebbe essere incentivato a ingannare gli utenti per farli fare clic sui suoi annunci e aumentare così il pagamento degli annunci (almeno per un breve periodo, finché la rete pubblicitaria non lo scopre).
In genere, questi annunci vengono pubblicati in iframe.
Ora, se il publisher volesse indurre gli utenti a fare clic su questi annunci, potrebbe rendere gli iframe degli annunci completamente trasparenti applicando una regola CSS iframe { opacity: 0; }
e sovrapponendoli a qualcosa di accattivante, ad esempio un video di un gatto carino su cui gli utenti vorrebbero fare clic.
Questo tipo di attacco si chiama clickjacking.
Puoi vedere un attacco di clickjacking in azione nella sezione superiore di questa
demo (prova a "guardare" il video del gatto
e attiva la "modalità trucco").
Noterai che l'annuncio nell'iframe "crede" di aver ricevuto clic legittimi, anche se era completamente trasparente quando hai fatto clic (fingendo di farlo involontariamente).
In che modo Intersection Observer v2 risolve il problema?
Intersection Observer v2 introduce il concetto di monitoraggio della "visibilità" effettiva di un elemento di destinazione come la definirebbe un essere umano.
Se imposti un'opzione nel
costruttore IntersectionObserver
,
le istanze di
IntersectionObserverEntry
intersecanti conterranno un nuovo campo booleano denominato isVisible
.
Un valore true
per isVisible
è una garanzia solida dell'implementazione di base
che l'elemento target non è completamente ostruito da altri contenuti
e non sono stati applicati effetti visivi che potrebbero alterare o distorcere la sua visualizzazione sullo schermo.
Al contrario, un valore false
indica che l'implementazione non può fornire questa garanzia.
Un dettaglio importante della
specifica
è che l'implementazione è consentita per segnalare falsi negativi (ovvero impostare isVisible
su false
anche quando l'elemento target è completamente visibile e non modificato).
Per motivi di prestazioni o altri, i browser si limitano a lavorare con caselle delimitanti e geometria rettangolare; non cercano di ottenere risultati perfetti a livello di pixel per modifiche come border-radius
.
Detto questo, i falsi positivi non sono consentiti in nessuna circostanza (ad esempio, l'impostazione di isVisible
su true
quando l'elemento target non è completamente visibile e non modificato).
Che aspetto ha il nuovo codice in pratica?
Il costruttore IntersectionObserver
ora accetta due proprietà di configurazione aggiuntive: delay
e trackVisibility
.
delay
è un numero che indica il ritardo minimo in millisecondi tra le notifiche dell'osservatore per un determinato target.
trackVisibility
è un valore booleano che indica se l'osservatore monitora le modifiche alla visibilità di un target.
È importante notare che quando trackVisibility
è true
, delay
deve essere almeno 100
(ovvero non più di una notifica ogni 100 ms).
Come accennato in precedenza, la visibilità è costosa da calcolare e questo requisito è una precauzione contro il degrado delle prestazioni e il consumo della batteria. Lo sviluppatore responsabile utilizzerà il
valore massimo tollerabile per il ritardo.
In base alle attuali specifiche, la visibilità viene calcolata nel seguente modo:
Se l'attributo
trackVisibility
dell'osservatore èfalse
, il target è considerato visibile. Questo corrisponde al comportamento attuale della versione 1.Se il target ha una matrice di trasformazione efficace diversa da una traduzione 2D o da un upscaling 2D proporzionale, il target è considerato invisibile.
Se il target o qualsiasi elemento della blockchain contenente ha un'opacità effettiva diversa da 1.0, il target è considerato invisibile.
Se al target o a un elemento della blockchain contenente sono stati applicati filtri, il target è considerato invisibile.
Se l'implementazione non può garantire che il target sia completamente libero da altri contenuti della pagina, il target è considerato invisibile.
Ciò significa che le implementazioni attuali sono piuttosto conservative in termini di garanzia della visibilità.
Ad esempio, l'applicazione di un filtro in scala di grigi quasi impercettibile come filter: grayscale(0.01%)
o l'impostazione di una trasparenza quasi invisibile con opacity: 0.99
rende l'elemento
invisibile.
Di seguito è riportato un breve esempio di codice che illustra le nuove funzionalità dell'API. Puoi vedere la logica di monitoraggio dei clic in azione nella seconda sezione della demo (ma ora prova a "guardare" il video del cucciolo). Assicurati di attivare di nuovo la "modalità di inganno" per trasformarti immediatamente in un publisher poco affidabile e scoprire in che modo Intersection Observer 2 impedisce il monitoraggio dei clic sugli annunci non legittimi. Questa volta, Intersection Observer v2 è dalla nostra parte. 🎉
<!DOCTYPE html>
<!-- This is the ad running in the iframe -->
<button id="callToActionButton">Buy now!</button>
// This is code running in the iframe.
// The iframe must be visible for at least 800ms prior to an input event
// for the input event to be considered valid.
const minimumVisibleDuration = 800;
// Keep track of when the button transitioned to a visible state.
let visibleSince = 0;
const button = document.querySelector('#callToActionButton');
button.addEventListener('click', (event) => {
if ((visibleSince > 0) &&
(performance.now() - visibleSince >= minimumVisibleDuration)) {
trackAdClick();
} else {
rejectAdClick();
}
});
const observer = new IntersectionObserver((changes) => {
for (const change of changes) {
// ⚠️ Feature detection
if (typeof change.isVisible === 'undefined') {
// The browser doesn't support Intersection Observer v2, falling back to v1 behavior.
change.isVisible = true;
}
if (change.isIntersecting && change.isVisible) {
visibleSince = change.time;
} else {
visibleSince = 0;
}
}
}, {
threshold: [1.0],
// 🆕 Track the actual visibility of the element
trackVisibility: true,
// 🆕 Set a minimum delay between notifications
delay: 100
}));
// Require that the entire iframe be visible.
observer.observe(document.querySelector('#ad'));
Link correlati
- Ultimo Editor's Draft della specifica Intersection Observer.
- Intersection Observer v2 su Stato della piattaforma Chrome.
- Bug di Chromium relativo a Intersection Observer v2.
- Lampeggia Intent to Implement posting.
Ringraziamenti
Grazie a Simeon Vincent, Yoav Weiss e Mathias Bynens per aver esaminato questo articolo, nonché a Stefan Zager per aver esaminato e implementato la funzionalità in Chrome. Immagine hero di Sergey Semin su Unsplash.