O Intersection Observer
é uma dessas APIs que provavelmente são amadas universalmente e podem ser usadas em todos os
principais navegadores. Os desenvolvedores usaram essa API para uma ampla variedade de casos de uso, incluindo carregamento lento de imagens e vídeos, notificações quando os elementos atingem position: sticky, acionamento de eventos de análise e muito mais.
Na forma mais básica, esta é a aparência da API Intersection Observer v1:
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'));
Desafios de visibilidade no Intersection Observer v1
Com a API Intersection Observer v1, é possível saber quando um elemento é rolado para a janela de visualização. No entanto, não é possível determinar se esse elemento está coberto por outro conteúdo da página, o que é chamado de oclusão, ou se o elemento aparece modificado por CSS, como transform, opacity ou filter, o que pode torná-lo invisível.
Para um elemento no documento de nível superior, essas informações podem ser determinadas analisando o DOM com JavaScript, por exemplo, com DocumentOrShadowRoot.elementFromPoint().
Por outro lado, as mesmas informações não podem ser obtidas se o elemento em questão estiver localizado em um iframe de terceiros.
Por que a visibilidade é importante?
Infelizmente, a Internet tem pessoas mal-intencionadas. Por exemplo, um editor desonesto pode usar anúncios de pagamento por clique em um site. Eles podem enganar os usuários para que cliquem nesses anúncios e ganhem mais dinheiro, pelo menos até que a rede de publicidade descubra o esquema. Normalmente, esses anúncios são veiculados em iframes.
Para enganar os usuários, o editor pode tornar os iframes de anúncios completamente transparentes com CSS: iframe { opacity: 0; }. Em seguida, eles podem colocar esses iframes transparentes sobre conteúdo atraente, como um vídeo de um gatinho fofo, que os usuários querem clicar.
Isso é chamado de clickjacking.
Você pode ver um ataque de clickjacking em ação na seção superior da nossa demonstração. Tente "assistir" ao vídeo do gato e ative o modo de truque. O anúncio no iframe registra cliques como legítimos, mesmo que você tenha clicado nele sem querer enquanto o iframe estava transparente.

Melhorias no Intersection Observer v2
O Intersection Observer v2 pode rastrear a "visibilidade" de um elemento como um humano a definiria. Se você definir uma opção no construtor
IntersectionObserver,
as instâncias
IntersectionObserverEntry
resultantes incluem um novo campo booleano chamado isVisible. Quando isVisible é true, o navegador garante que o elemento não esteja coberto por outro conteúdo e não tenha efeitos visuais que ocultem ou mudem a exibição. Se isVisible for false, o navegador não poderá fazer essa garantia.
A
especificação
permite falsos negativos: isVisible pode ser false mesmo quando o elemento está
realmente visível e inalterado. Para melhorar o desempenho, os navegadores usam cálculos mais simples, como caixas delimitadoras e formas retangulares, e não verificam todos os pixels em busca de detalhes complexos, como border-radius.
No entanto, não são permitidos falsos positivos em nenhuma circunstância. Isso significa que isVisible não será true se o elemento não estiver completamente visível e sem modificações.
Aplicar essas mudanças
O construtor IntersectionObserver agora usa mais duas propriedades de configuração:
delayé um número que indica o atraso mínimo em milissegundos entre notificações do observador para um determinado destino.trackVisibilityé um booleano para indicar se o observador vai rastrear mudanças na visibilidade de um destino.
Quando trackVisibility é true, delay precisa ser definido como 100 ou um valor maior (ou seja, não mais de uma notificação a cada 100 ms).
Como a visibilidade é cara de calcular, essa é uma precaução contra a degradação do desempenho e o consumo da bateria. Os desenvolvedores responsáveis devem usar o maior valor tolerável para o atraso.
A especificação calcula a visibilidade. Assim como na versão 1, quando o atributo trackVisibility
do observador é false, o destino é considerado visível.
Na versão 2, o destino é considerado invisível se:
Ela tem uma matriz de transformação efetiva, que não seja uma translação 2D ou um aumento proporcional 2D.
O destino ou qualquer elemento na cadeia de blocos que o contém tem uma opacidade efetiva menor que 1,0.
O destino ou qualquer elemento na cadeia de blocos que o contém tem filtros aplicados.
Se a implementação não puder garantir que o destino não esteja completamente obstruído por outro conteúdo da página.
Isso significa que as implementações atuais são bastante conservadoras para garantir a visibilidade. Por exemplo, aplicar um filtro de escala de cinza quase imperceptível (filter: grayscale(0.01%)) ou definir a menor transparência (opacity: 0.99) tornaria o elemento invisível.
Confira um exemplo de código que ilustra os novos recursos da API. Você pode conferir a lógica de rastreamento de cliques em ação na segunda seção da demonstração. Tente "assistir" ao vídeo do cachorrinho. Ative o modo de truque para se transformar em um usuário de má-fé e ver como o Intersection Observer v2 impede que cliques em anúncios não legítimos sejam rastreados. O Intersection Observer v2 nos protege.

<!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 v2, fallback 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'));
Outros recursos
- Rascunho de trabalho do Intersection Observer.
- Intersection Observer v2 no Status da plataforma do Chrome.
Agradecimentos
Agradecemos a Simeon Vincent, Yoav Weiss e Mathias Bynens pela revisão, além de Stefan Zager pela revisão e implementação do recurso no Chrome.