Intersection Observer v2 adiciona a capacidade de não apenas observar as interseções em si, mas também detectar se o elemento em interseção estava visível no momento da interseção.
Intersection Observer v1 é uma daquelas APIs que provavelmente é muito adotada por todos. Agora que
O Safari também é compatível com esse recurso,
ele também pode ser usado em todos os principais navegadores. Para relembrar brevemente a API,
recomendo assistir os vídeos do Surma
Microponta supercarregada em intersecções
Observador v1 incorporado abaixo.
Você também pode ler o artigo detalhado de Surma
artigo.
As pessoas já usaram o Intersection Observer v1 em uma ampla variedade de casos de uso, como
carregamento lento de imagens e vídeos;
receber notificações quando os elementos chegarem a position: sticky
;
disparar eventos do Analytics,
e muito mais.
Para saber todos os detalhes, confira a Documentos do Intersection Observer sobre MDN, mas como um breve lembrete, a API Intersection Observer v1 é parecida com a caso 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'));
Quais são as dificuldades do Intersection Observer v1?
Para deixar claro, Intersection Observer v1 é ótimo, mas não é perfeito. Existem
alguns casos extremos em que a API não é suficiente. Vamos dar uma olhada mais de perto!
A API Intersection Observer v1 informa quando um elemento é rolado até a seção
janela de visualização da janela, mas não informa se o elemento está coberto
por qualquer outro conteúdo da página (ou seja, quando o elemento está obstruído) ou pela
a exibição visual do elemento foi modificada por efeitos visuais como transform
, opacity
,
filter
etc., o que pode efetivamente torná-lo invisível.
Para um elemento do documento de nível superior, essas informações podem ser determinadas pela análise
o DOM via JavaScript, por exemplo, por meio do
DocumentOrShadowRoot.elementFromPoint()
e, em seguida, ir mais fundo.
Em contraste, as mesmas informações não podem ser obtidas se o elemento em questão for
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 intenções piores.
Por exemplo, um editor suspeito que veicula anúncios de pagamento por clique em um site de conteúdo pode ser incentivado
para induzir as pessoas a clicar em seus anúncios a fim de aumentar o pagamento de anúncios do editor (pelo menos
por um curto período, até que a rede de publicidade os capture).
Normalmente, esses anúncios são exibidos em iframes.
Agora, se o editor quisesse que os usuários clicassem em tais anúncios, ele poderia tornar os iframes de anúncio
completamente transparente aplicando uma regra CSS iframe { opacity: 0; }
e sobrepondo os iframes.
em cima de algo atraente, como um vídeo fofo de gato em que os usuários realmente querem clicar.
Isso é chamado de clickjacking.
Você pode ver esse ataque de clickjacking em ação na seção superior deste
demo (tente "assistir" o vídeo do gato)
e ative o "modo travessura").
Você notará que o anúncio no iframe "pensa" recebeu cliques legítimos, mesmo que tenha sido
completamente transparente quando você clicou nele (finge ser involuntariamente).
Como o Intersection Observer v2 corrige isso?
Intersection Observer v2 apresenta o conceito de rastreamento da "visibilidade" real de um alvo
elemento que um ser humano o definiria.
Ao definir uma opção no
construtor IntersectionObserver
,
se cruzando
IntersectionObserverEntry
instâncias conterá um novo campo booleano chamado isVisible
.
Um valor true
para isVisible
é uma forte garantia da implementação
que o elemento de destino esteja completamente desobstruído por outro conteúdo
e não tem efeitos visuais que possam alterar ou distorcer a exibição na tela.
Por outro lado, um valor false
significa que a implementação não pode garantir essa garantia.
Um detalhe importante da
spec (link em inglês)
é que a implementação tem permissão para informar falsos negativos (ou seja, definir isVisible
como false
, mesmo quando o elemento de destino está completamente visível e inalterado).
Por motivos de desempenho ou por outros motivos, os navegadores se limitam a trabalhar com delimitadores.
caixas 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, configurar
isVisible
como true
quando o elemento de destino não está completamente visível e não modificado).
Como será o novo código na prática?
O construtor IntersectionObserver
agora usa mais duas propriedades de configuração: delay
e trackVisibility
.
O delay
é um número que indica o atraso mínimo em milissegundos entre as notificações da
o observador de um determinado alvo.
O trackVisibility
é um booleano que indica se o observador rastreará as mudanças na meta
visibilidade.
É importante observar que quando trackVisibility
for true
, delay
precisará estar em
no mínimo 100
(ou seja, no máximo uma notificação a cada 100 ms).
Como observado antes, 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 vai usar
maior valor tolerável para atraso.
De acordo com a spec, a visibilidade é calculada da seguinte forma:
Se o atributo
trackVisibility
do observador forfalse
, o alvo será considerado visível. Isso corresponde ao comportamento atual da v1.Se o destino tiver uma matriz de transformação eficaz que não seja uma tradução 2D ou o aumento proporcional de 2D, o destino será considerado invisível.
Se o destino, ou qualquer elemento na cadeia de blocos que o contém, tiver uma opacidade efetiva diferente 1,0, o alvo será considerado invisível.
Se o destino, ou qualquer elemento na cadeia de bloqueio que o contém, tiver filtros aplicados, o alvo é considerado invisível.
Se a implementação não puder garantir que a segmentação não seja totalmente obstruída por outra página o alvo 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 de escala de cinza quase imperceptível como filter: grayscale(0.01%)
ou definir uma transparência quase invisível com opacity: 0.99
renderizaria o elemento.
invisível.
Veja abaixo um breve exemplo de código que ilustra os novos recursos da API. É possível conferir o rastreamento de cliques em ação na segunda seção da demonstração (mas agora, tente "assistir" ao vídeo do cachorrinho). Não se esqueça de ativar o "modo de truques" de novo para imediatamente Transforme-se em um editor suspeito e veja como o Intersection Observer v2 que cliques não legítimos sejam acompanhados. Desta vez, o Intersection Observer v2 está de volta. 🎉
<!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
- Último rascunho do editor do Especificações do Intersection Observer.
- Intersection Observer v2 ativado Status da Plataforma Chrome.
- Bug do Chromium do Intersection Observer v2.
- Piscar Intenção de implementar a postagem.
Agradecimentos
Agradecemos a Simeon Vincent, Yoav Weiss e Mathias Bynens por revisar este artigo, bem como Stefan Zager para revisar e implementar o recurso no Chrome. Imagem principal de Sergey Semin no Unsplash.