Güvenmek iyidir, gözlem daha iyi: Intersection Observer v2

Kesişim Gözlemcisi v2, sadece kesişimleri hem gözlemleme hem de kesişen öğenin kesişim sırasında görünür olup olmadığını tespit etme özelliğini ekler.

Intersection Observer v1, muhtemelen evrensel olarak sevilen API'lerden biridir ve artık Safari de desteklediği için, nihayet tüm önemli tarayıcılarda evrensel olarak kullanılabilir. API ile ilgili bilgilerinizi hızlıca tazelemek için Surma'nın aşağıya yerleştirilmiş IntersectionObserver v1 ile ilgili Supercharged Microtip başlıklı videosunu izlemenizi öneririz. Surma'nın ayrıntılı makalesini de okuyabilirsiniz. Kullanıcılar, resim ve videoların geç yüklenmesi, öğeler position: sticky değerine ulaştığında bildirim alma, analiz etkinliklerini tetikleme ve daha birçok kullanım alanı için Intersection Observer'dan yararlanıyor.

Tüm ayrıntılar için Intersection Observer docs on MDN (MDN'deki Intersection Observer belgeleri) sayfasına göz atın. Ancak Intersection Observer v1 API'nin en temel durumda nasıl göründüğünü hatırlatmak isteriz:

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'));

Intersection Observer v1'in zorluğu nedir?

Açıkça belirtmek gerekirse Intersection Observer v1 çok iyi bir çözüm ama mükemmel değil. API'nin yetersiz kaldığı bazı durumlar vardır. Daha yakından inceleyelim. Intersection Observer v1 API'si, bir öğe pencerenin görüntü alanına kaydırıldığında size bilgi verebilir. Ancak, öğenin başka bir sayfa içeriği tarafından kaplanıp kaplanmadığını (yani, öğe kapandığında) veya öğenin görsel görünümünün, etkili bir şekilde görünmez hale getirebilecek transform, opacity, filter gibi görsel efektlerle değiştirilip değiştirilmediğini belirtmez.

Üst düzey belgedeki bir öğede bu bilgiler, DOM'un JavaScript aracılığıyla analiz edilmesi (ör. DocumentOrShadowRoot.elementFromPoint() aracılığıyla) ve ardından daha ayrıntılı inceleme yapılarak belirlenebilir. Öte yandan, söz konusu öğe bir üçüncü taraf iframe'inde yer alıyorsa aynı bilgiler elde edilemez.

Gerçek görünürlük neden bu kadar önemli?

Maalesef İnternet, kötü niyetli kişileri kendine çeken bir yerdir. Örneğin, bir içerik sitesinde tıklama başına ödeme reklamları sunan şüpheli bir yayıncı, yayıncının reklam ödemesini artırmak amacıyla kullanıcıları kandırarak reklamlarını tıklamaları için teşvik edilebilir (en azından kısa bir süre için (reklam ağı bunları yakalayana kadar)). Genellikle, bu tür reklamlar iframe'ler içinde sunulur. Yayıncı, kullanıcıların bu tür reklamları tıklamalarını sağlamak isterse, bir CSS kuralı iframe { opacity: 0; } uygulayarak ve iframe'leri, kullanıcıların gerçekten tıklamak isteyeceği şirin bir kedi videosu gibi çekici bir şeyin üzerine yerleştirerek reklam iframe'lerini tamamen şeffaf hale getirebilir. Buna tıklama korsanlığı denir. Bu tür bir tıklama korsanlığı saldırısını bu demonun üst bölümünde görebilirsiniz (kedi videosunu "izlemeyi" deneyin ve "şaka modunu" etkinleştirin). iframe'deki reklamın geçerli tıklamalar aldığını "düşündüğünü", (istemsiz şekilde tıkladığınızda) tamamen şeffaf olduğunu fark edersiniz.

Reklamı şeffaf bir şekilde biçimlendirip ilgi çekici bir öğenin üzerine yerleştirerek kullanıcıyı kandırarak reklamı tıklamasını sağlama.

Intersection Observer v2 bu sorunu nasıl düzeltir?

Kesişim Gözlemleyicisi v2, hedef öğenin bir insanın tanımlayacağı şekilde gerçek "görünürlüğünü" izleme kavramını ortaya çıkarır. IntersectionObserver oluşturucuda bir seçenek ayarlandığında, IntersectionObserverEntry örneklerinin kesiştiği isVisible adlı yeni bir boole alanı içerir. isVisible için bir true değeri, temel uygulamada hedef öğenin başka içeriklerle tamamen kapatılmadığını ve ekrandaki görünümünü değiştirecek veya bozacak görsel efektlerin uygulanmadığını belirten güçlü bir garantidir. false değeri ise uygulamanın bu garantiyi veremeyeceği anlamına gelir.

spec önemli bir ayrıntısı, uygulamaya yanlış negatifleri bildirmesine izin verilmesidir (yani, hedef öğe tamamen görünür ve değiştirilmemiş olsa bile isVisible değerini false olarak ayarlama). Performans veya başka nedenlerle, tarayıcılar kendilerini sınırlayıcı kutular ve doğrusal geometriyle çalışmakla sınırlar; border-radius gibi değişiklikler için mükemmel pikseller elde etmeye çalışmazlar.

Bununla birlikte, yanlış pozitiflere hiçbir koşulda izin verilmez (yani hedef öğe tamamen görünür ve değiştirilmemişken isVisible değerini true olarak ayarlayın).

Yeni kod pratikte nasıl görünüyor?

IntersectionObserver oluşturucu artık iki ek yapılandırma özelliği alır: delay ve trackVisibility. delay, belirli bir hedef için gözlemciden gelen bildirimler arasındaki milisaniye cinsinden minimum gecikmeyi gösteren bir sayıdır. trackVisibility, gözlemcinin hedefin görünürlüğündeki değişiklikleri izleyip izlemeyeceğini gösteren bir boole'dir.

trackVisibility değeri true olduğunda delay değerinin en az 100 (yani 100 ms'de bir en fazla bir bildirim) olması gerektiği unutulmamalıdır. Daha önce belirtildiği gibi, görünürlüğün hesaplanması pahalıdır ve bu gereklilik, performans düşüşü ve pil tüketimine karşı bir önlemdir. Sorumlu geliştirici gecikme için en büyük tolere edilebilir değeri kullanır.

Görünürlük mevcut spec göre aşağıdaki gibi hesaplanır:

  • Gözlemcinin trackVisibility özelliği false ise hedef görünür olarak kabul edilir. Bu, geçerli v1 davranışına karşılık gelir.

  • Hedefin 2D çeviri veya orantılı 2D büyütme dışında etkili bir dönüşüm matrisi varsa hedef görünmez olarak kabul edilir.

  • Hedef veya içerdiği blok zincirindeki herhangi bir öğe, 1,0 dışında bir etkili opaklığa sahipse hedef görünmez olarak kabul edilir.

  • Hedefte veya içerdiği blok zincirindeki herhangi bir öğeye filtre uygulanmışsa hedef görünmez olarak kabul edilir.

  • Uygulama, hedefin başka sayfa içeriği tarafından tamamen kapatılacağını garanti edemezse hedef görünmez olarak kabul edilir.

Bu, mevcut uygulamaların oldukça konservatif olduğu ve görünürlüğü garanti altına aldığı anlamına gelir. Örneğin, filter: grayscale(0.01%) gibi neredeyse fark edilmeyecek bir gri tonlama filtresi uygulamak veya opacity: 0.99 ile neredeyse görünmez bir şeffaflık ayarlamak, öğeyi görünmez hale getirir.

Aşağıda, yeni API özelliklerini gösteren kısa bir kod örneği verilmiştir. Tıklama izleme mantığının nasıl çalıştığını demonun ikinci bölümünde görebilirsiniz (ancak şimdi yavru köpek videosunu "izlemeyi" deneyin). Kendinizi hemen şüpheli bir yayıncıya dönüştürmek ve Intersection Observer v2'nin meşru olmayan reklam tıklamalarının izlenmesini nasıl önlediğini görmek için "numara modu"nu tekrar etkinleştirdiğinizden emin olun. Bu kez Intersection Observer v2'de sizi bekliyor. 🎉

Reklamda istenmeyen tıklamayı engelleyen Kavşak Gözlemcisi v2.

<!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'));

Teşekkür

Bu makaleyi değerlendirdikleri için Simeon Vincent, Yoav Weiss ve Mathias Bynens'e, ayrıca bu özelliği Chrome'da inceleyip uygulamaya koydukları için Stefan Zager'a teşekkür ederiz. Sergey Semin'in Unsplash'ta çektiği hero resim.