O Intersection Observer v2 adiciona a capacidade não apenas de observar interseções individuais, mas também de detectar se o elemento de interseção estava visível no momento da interseção.
A Intersection Observer v1 é uma das APIs que provavelmente foi muito usada por todos e, agora que o
Safari é compatível,
ela também pode ser usada em todos os principais navegadores. Para uma atualização rápida da API,
recomendamos assistir a Supercharged Microtip
da Surma no Intersection
Observer v1 incorporada abaixo.
Você também pode ler o artigo detalhado do Surma.
As pessoas usaram o Intersection Observer v1 para diversos casos de uso, como
carregamento lento de imagens e vídeos,
notificações quando os elementos atingem position: sticky
,
disparo de eventos de análise
e muito mais.
Para saber mais detalhes, consulte os documentos do Intersection Observer no MDN, mas como um lembrete rápido, a API Intersection Observer v1 é assim no caso mais básico:
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'));
Qual é o desafio do Intersection Observer v1?
Para esclarecer, o Intersection Observer v1 é ótimo, mas não é perfeito. Há alguns casos específicos em que a API fica aquém. Vamos conferir mais detalhes.
A API Intersection Observer v1 pode informar quando um elemento é rolado até a
janela de visualização da janela, mas não informa se ele está coberto
por outro conteúdo da página (ou seja, quando está oculto) ou se
a exibição visual do elemento foi modificada por efeitos visuais como transform
, opacity
,
filter
etc., o que efetivamente pode torná-lo invisível.
Para um elemento no documento de nível superior, essas informações podem ser determinadas analisando
o DOM via JavaScript, por exemplo, via
DocumentOrShadowRoot.elementFromPoint()
e fazendo uma análise mais detalhada.
Por outro lado, as mesmas informações não poderão ser obtidas se o elemento em questão estiver localizado em um iframe de terceiros.
Por que a visibilidade real é tão importante?
Infelizmente, a Internet é um lugar que atrai usuários de má-fé com más intenções.
Por exemplo, um editor duvidoso que veicula anúncios de pagamento por clique em um site de conteúdo pode ser incentivado a induzir as pessoas a clicar nos anúncios para aumentar o pagamento do anúncio do editor (pelo menos por um curto período, até que a rede de publicidade as capture).
Normalmente, tais anúncios são veiculados em iframes.
Agora, se o editor quiser que os usuários cliquem nesses anúncios, ele poderia deixar os iframes do anúncio
completamente transparentes aplicando uma regra CSS iframe { opacity: 0; }
e sobrepondo os iframes
sobre algo atraente, como um vídeo de gato fofo em que os usuários realmente clicariam.
Isso é chamado de clickjacking.
Confira esse ataque de clickjacking em ação na seção superior desta demonstração. Tente "assistir" o vídeo de gato e ative o "modo de truques".
Você notará que o anúncio no iframe "acha" que recebeu cliques legítimos, mesmo que tenha sido completamente transparente quando você (finja-involuntariamente) clicou nele.
Como o Intersection Observer v2 corrige isso?
O Intersection Observer v2 apresenta o conceito de rastrear a "visibilidade" real de um elemento
de destino como um ser humano o definiria.
Ao definir uma opção no
construtor IntersectionObserver
,
a interseção das instâncias
IntersectionObserverEntry
conterá um novo campo booleano chamado isVisible
.
Um valor true
para isVisible
é uma forte garantia da implementação subjacente
de que o elemento de destino não está completamente oculto por outro conteúdo
e não tem efeitos visuais aplicados que alterariam ou distorceriam a exibição na tela.
Por outro lado, um valor false
significa que a implementação não pode fazer essa garantia.
Um detalhe importante da
spec
é que a implementação tem permissão para informar falsos negativos, ou seja, definir isVisible
como false
mesmo quando o elemento de destino estiver completamente visível e não modificado.
Por motivos de desempenho ou por outros motivos, os navegadores se limitam a trabalhar com caixas delimitadoras e geometria retilínea. Eles não tentam alcançar resultados perfeitos para modificações como border-radius
.
Dito isso, falsos positivos não são permitidos em nenhuma circunstância, ou seja, definir
isVisible
como true
quando o elemento de destino não estiver completamente visível e não tiver sido modificado.
Como é o novo código na prática?
O construtor IntersectionObserver
agora usa duas outras propriedades de configuração: delay
e trackVisibility
.
O delay
é um número que indica o atraso mínimo em milissegundos entre as notificações do
observador para um determinado destino.
O trackVisibility
é um booleano que indica se o observador vai rastrear as mudanças na visibilidade
de um destino.
É importante observar que, quando trackVisibility
é true
, delay
precisa ser pelo menos 100
, ou seja, no máximo uma notificação a cada 100 ms.
Conforme observado anteriormente, o cálculo da visibilidade é caro, e esse requisito é uma precaução contra
degradação do desempenho e consumo da bateria. O desenvolvedor responsável usará o maior valor tolerável para o atraso.
De acordo com a spec atual, a visibilidade é calculada da seguinte forma:
Se o atributo
trackVisibility
do observador forfalse
, o destino será considerado visível. Isso corresponde ao comportamento atual da v1.Se o destino tiver uma matriz de transformação efetiva que não seja uma translação 2D ou um aumento 2D proporcional, o destino será considerado invisível.
Se o destino ou qualquer elemento na cadeia de blocos dele tiver uma opacidade efetiva diferente de 1.0, o destino será considerado invisível.
Se o destino ou qualquer elemento na cadeia de blocos dele tiver filtros aplicados, o destino será considerado invisível.
Se a implementação não puder garantir que o destino não esteja completamente oculto por outro conteúdo da página, ele será considerado invisível.
Isso significa que as implementações atuais são bastante conservadoras com a garantia de visibilidade.
Por exemplo, aplicar um filtro em escala de cinza quase imperceptível, como filter: grayscale(0.01%)
,
ou definir uma transparência quase invisível com opacity: 0.99
, tornaria o elemento
invisível.
Abaixo está um pequeno exemplo de código que ilustra os novos recursos da API. Veja a lógica de rastreamento de cliques em ação na segunda seção da demonstração. Agora, tente "assistir" o vídeo do filhote. Ative o "modo de truques" novamente para se converter imediatamente em um editor suspeito e veja como o Intersection Observer v2 impede o rastreamento de cliques não legítimos em anúncios. Desta vez, o Intersection Observer v2 voltou! 🎉
<!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'));
Links relacionados
- Rascunho mais recente do editor da especificação do Intersection Observer (em inglês).
- Intersection Observer v2 no Status da plataforma do Chrome (em inglês).
- Bug do Chromium do Intersection Observer v2.
- Pisque Intent de implementar postagem.
Agradecimentos
Agradecemos a Simeon Vincent, Yoav Weiss e Mathias Bynens por revisarem este artigo. Também agradecemos a Stefan Zager por analisar e implementar o recurso no Chrome. Imagem principal de Sergey Semin no Unsplash.