Intersection Observer v2 不僅新增可逐一觀察交叉點的功能,還能 偵測交集時是否可見交集元素。
Intersection Observer 1.0 版是可能受到大眾喜愛的 API 之一
Safari 支援
此 API 終於適用於所有主要瀏覽器如果需要快速複習 API
我推薦觀看Surma的
交集的Supercharged Microtip
在下方嵌入的 Observer v1。
此外,你也能閱讀《Surma》的深入解說
文章。
使用者將 Intersection Observer v1 用於多種用途,例如
延遲載入圖片和影片
在元素達到 position: sticky
時接收通知
觸發 Analytics 事件
以及其他工具
如需完整詳細資料,請參閱 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()
敬上
然後再進一步研究
相反地,如果相關元素
位於第三方 iframe 中
為什麼實際曝光率這麼高?
可惜的是,網際網路已經吸引了意圖更惡劣的惡意行為人。
舉例來說,如果某個可疑的發布商在內容網站上放送每次點擊付費廣告,就可能獲得利誘
以誘騙使用者點擊其廣告,以提高發布商的廣告支付金額 (至少
短暫的空檔,直到廣告聯播網成功擷取到這些流量為止)。
這類廣告通常會透過 iframe 放送。
現在,如果發布商想吸引使用者點擊這類廣告,可以將廣告設為 iframe
套用 CSS 規則 iframe { opacity: 0; }
並重疊 iframe,以完全透明的方式
再加上有吸引力的內容
例如使用者可能願意點閱的可愛貓咪影片
這就是所謂的「點擊劫持」。
您可以在本頁面上方的章節看到此次點擊劫持攻擊實際運作
示範 (嘗試「觀看」該貓咪的影片
並啟用「模擬模式」)。
您會注意到 iframe 中的廣告廣告也獲得正常點擊,
而且完全透明。
Intersection Observer v2 如何解決這個問題?
Intersection Observer 第 2 版介紹了追蹤實際「可視性」的概念的目標
視為由人定義
只要在
IntersectionObserver
建構函式、
交集
IntersectionObserverEntry
。
執行個體則會包含名為 isVisible
的新布林值欄位。
isVisible
的 true
值是基礎實作所提供的強大保證
其他內容完全遮住目標元素
且未套用任何會改變或扭曲顯示畫面的視覺效果。
相反地,false
值則代表實作項目無法保證。
另外要介紹
規格
的導入方式「可以」回報偽陰性 (也就是說,將 isVisible
設為
至 false
)。
基於效能或其他原因,瀏覽器會限制自身使用邊界功能
方塊和直線幾何圖形;不必為網站取得完美像素結果
例如 border-radius
。
也就是說,在任何情況下 (亦即
如果目標元素並未完全顯示且未經修改,則將 isVisible
變更為 true
。
實際的新程式碼看起來會是什麼樣子?
IntersectionObserver
建構函式現在採用兩種額外設定屬性:delay
和 trackVisibility
。
delay
是一個數字,表示發出通知的最短延遲時間 (以毫秒為單位)
預測特定目標的觀察器
trackVisibility
是一個布林值,指出觀察器是否會追蹤目標的變動
曝光率。
請特別注意,當 trackVisibility
為 true
時,delay
必須在
至少 100
(也就是每 100 毫秒不超過一則通知)。
如先前所述,可見度的計算成本高昂,而且這個要求是預防措施
效能降低和電池耗電量負責任開發人員使用
最大可容許的值。
根據 spec,顯示設定是 計算方式如下:
如果觀察器的
trackVisibility
屬性為false
,則系統會將目標視為可見。 這與目前的第 1 版行為相符。目標是否具備有效轉換矩陣而非 2D 轉譯 或比例的 2D 放大功能,系統會將目標視為隱藏。
如果目標或所含區塊鏈中的任何元素,具有有效透明度時 1.0,系統會將目標視為隱藏。
如果目標或所含區塊鏈中的任何元素套用了任何篩選器, 那麼目標就視為不可見
如果實作結果無法保證其他網頁完全遮住目標 內容就視為不可見。
這表示目前的實作方式較為保守,且能保證可見度。
例如,套用 filter: grayscale(0.01%)
這類幾乎難以察覺的灰階濾鏡
或使用 opacity: 0.99
設定幾乎看不見的透明度
隱形
以下提供簡短的程式碼範例,說明新的 API 功能。就可以看到 示範 (但現在請試著「觀看」該小狗影片)。請務必啟用「模擬模式」再次 把自己變成可疑的發布商,看看 Intersection Observer 第 2 版如何防止你入侵 避免追蹤非正當的廣告點擊。 這次,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'));
相關連結
- 最新編輯的草稿 交集觀察器規格。
- Intersection Observer v2 開啟 Chrome 平台狀態。
- Intersection Observer v2 v2 Chromium 錯誤。
- 閃爍 打算導入貼文功能。
特別銘謝
非常感謝 Simeon Vincent, Yoav Weiss 和 Mathias Bynens 查看這篇文章,另外也包括 Stefan Zager 在 Chrome 中查看及實作這項功能。 主頁橫幅由 Sergey Semin 提供 Unsplash 網站上。