신뢰는 좋고 관찰은 더 좋습니다: Intersection Observer v2

Intersection Observer v2는 교차점 자체를 관찰할 뿐만 아니라 교차 시점에 교차 요소가 표시되었는지 감지합니다.

Intersection Observer v1은 보편적으로 애용되는 API 중 하나입니다. Safari도 지원됩니다. 또한 최종적으로 모든 주요 브라우저에서 보편적으로 사용할 수 있습니다. API를 빠르게 복습하기 위해 Surma의 교차로에 대한 강력한 마이크로팁 아래에 삽입된 Observer v1입니다. 수르마의 심층 탐구를 읽고 도움말을 참조하세요. 사람들은 다음과 같은 다양한 사용 사례에 Intersection Observer v1을 사용했습니다. 이미지 및 동영상 지연 로드 요소가 position: sticky에 도달하면 알림을 받음 분석 이벤트 실행, 기타 등등

자세한 내용은 MDN의 Intersection Observer 문서, 참고로 Intersection Observer v1 API는 가장 일반적으로 다음과 같은 모습입니다. 기본 사례:

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에서 어려운 점은 무엇인가요?

Intersection Observer v1은 좋지만 완벽하지는 않습니다. 현재 API가 부족한 일부 특수한 사례를 살펴보겠습니다 좀 더 자세히 살펴보겠습니다! Intersection Observer v1 API는 요소가 요소의 표시 여부는 알 수 없습니다. 요소가 가려졌을 때) 또는 요소의 시각적 표시가 transform, opacity, filter 등은 실질적으로 표시되지 않도록 할 수 있습니다.

최상위 문서에 있는 요소의 경우 이 정보는 JavaScript를 통해 DOM을 사용할 수 있습니다(예: DocumentOrShadowRoot.elementFromPoint() 드림 더 깊이 파고 들어가면 됩니다. 반대로, 문제가 되는 요소가 제3자 iframe에 있습니다.

실제 가시성이 중요한 이유는 무엇일까요?

안타깝게도 인터넷은 나쁜 의도로 악의적인 행위자를 끌어들이는 공간입니다. 예를 들어 콘텐츠 사이트에 클릭당지불 광고를 게재하는 부적절한 게시자는 인센티브를 받을 수 있습니다. 사람들이 광고를 클릭하도록 속여서 게시자의 광고 지불 금액을 광고 네트워크가 포착할 때까지 단기간 동안) 일반적으로 이러한 광고는 iframe으로 게재됩니다. 사용자가 이러한 광고를 클릭하도록 하려면 게시자가 광고 iframe을 만들어 CSS 규칙 iframe { opacity: 0; }을 적용하고 iframe을 오버레이하여 완전히 투명하게 예를 들어 사용자가 클릭하고 싶어 할 만한 귀여운 고양이 동영상 같은 매력적인 콘텐츠를 추가하세요. 이를 클릭재킹이라고 합니다. 이 도움말의 상단에서 이러한 클릭재킹 공격이 실제로 실행되고 있음을 demo (고양이 동영상 '시청' 시도 '트릭 모드')를 활성화합니다. iframe의 광고가 실제로 (무의식적으로 가장) 클릭했을 때 완전히 투명하게 공개되도록 할 수 있습니다.

투명한 스타일을 지정하고 매력적인 내용 위에 오버레이하여 사용자가 광고를 클릭하도록 속입니다.

Intersection Observer v2에서는 이 문제를 어떻게 해결하나요?

Intersection Observer v2에서 실제 '가시성'을 추적하는 개념 도입 (대상의) 그것을 정의하는 것입니다. 타겟팅 기준에서 옵션을 IntersectionObserver 생성자, 교차 IntersectionObserverEntry 그러면 인스턴스에 isVisible라는 새로운 불리언 필드가 포함됩니다. isVisibletrue 값은 기본 구현에서 강력하게 보장합니다. 타겟 요소가 다른 콘텐츠에 의해 완전히 가려지지 않음 화면에서 디스플레이를 변경하거나 왜곡하는 시각 효과가 적용되지 않습니다. 반대로 false 값은 구현에서 이를 보장할 수 없음을 의미합니다.

Kubernetes의 사양 구현이 거짓음성을 보고하도록 허용된다는 점 (즉, isVisible 대상 요소가 완전히 표시되고 수정되지 않은 경우에도 false로 변경됩니다. 성능 또는 기타 이유로 브라우저는 경계만 사용하도록 제한됩니다. 상자 및 직선 기하학 완벽한 픽셀의 결과를 얻으려고 border-radius와 같은 수정사항 포함

그렇지만 거짓양성은 어떤 경우에도 허용되지 않습니다. 즉, 타겟 요소가 완전히 표시되지 않거나 수정되지 않은 경우 isVisible에서 true로 변환)

새로운 코드는 실제로 어떤 모습일까요?

이제 IntersectionObserver 생성자가 두 개의 추가 구성 속성(delay)을 사용합니다. 및 trackVisibility delay는 지정된 타겟의 관찰자입니다. trackVisibility는 관찰자가 타겟의 변경사항을 추적할지 여부를 나타내는 불리언입니다. 가시성을 제공합니다

trackVisibilitytrue일 때 delay는 최소 100 (즉, 100ms마다 알림 1개 이하) 앞서 언급했듯이 가시성은 계산 비용이 많이 들고, 이러한 요구사항은 성능 저하 및 배터리 소모가 줄어듭니다. 책임 있는 개발자는 최대 허용 값을 반환합니다.

현재 사양일 경우 공개 상태는 다음과 같이 계산됩니다.

  • 관찰자의 trackVisibility 속성이 false이면 타겟이 표시되는 것으로 간주됩니다. 이는 현재 v1 동작에 해당합니다.

  • 대상에 2D 변환 이외의 유효한 변환 행렬이 있는 경우 또는 비례 2D 업스케일링인 경우 대상은 보이지 않는 것으로 간주됩니다.

  • 타겟 또는 타겟에 포함된 블록 체인의 요소가 1.0인 경우 타겟이 보이지 않는 것으로 간주됩니다.

  • 타겟 또는 타겟에 포함된 블록 체인의 요소에 필터가 적용된 경우 대상은 보이지 않는 것으로 간주됩니다.

  • 구현이 타겟이 다른 페이지에 의해 완전히 가려지지 않는다고 보장할 수 없는 경우 콘텐츠가 있는 경우 대상은 보이지 않는 것으로 간주됩니다.

즉, 현재 구현은 가시성을 보장하기 위해 상당히 보수적임을 의미합니다. 예를 들어 filter: grayscale(0.01%)와 같이 거의 눈에 띄지 않는 그레이 스케일 필터를 적용합니다. 또는 opacity: 0.99를 사용하여 거의 보이지 않는 투명도를 설정하면 모든 요소가 렌더링됩니다. 보이지 않습니다.

다음은 새로운 API 기능을 보여주는 간단한 코드 샘플입니다. 클릭 추적을 확인할 수 있습니다. 실제 로직은 데모의 두 번째 섹션에 나와 있습니다. (지금은 강아지 동영상을 '시청'해 보세요.) '트릭 모드'를 활성화해야 합니다 다시 한 번 어두운 게시자로 전환하고 Intersection Observer v2가 불법적인 광고 클릭 추적이 방지됩니다. 이번에는 Intersection Observer v2가 도움이 되었습니다. 🎉

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

감사의 말씀

사이먼 빈센트 덕분에 요아브 바이스, Mathias Bynens 이 기사의 검토자인 Stefan Zager와 감사합니다. 히어로 이미지: Sergey Semin(Unsplash).