Intersection Observer v2 добавляет возможность не только наблюдать за перекрестками как таковыми, но и определять, был ли виден пересекающий элемент в момент пересечения.
Intersection Observer v1 — один из тех API, который, вероятно, любим всеми, и теперь, когда Safari также поддерживает его , он наконец-то стал универсальным во всех основных браузерах. Для быстрого обновления API я рекомендую посмотреть Surma 's Supercharged Microtip on Intersection Observer v1, который встроен ниже. Вы также можете прочитать подробную статью Surma. Люди использовали Intersection Observer v1 для широкого спектра вариантов использования, таких как отложенная загрузка изображений и видео , получение уведомлений, когда элементы достигают position: sticky
, запуск событий аналитики и многое другое.
Подробную информацию можно найти в документации Intersection Observer на MDN , но в качестве краткого напоминания вот как выглядит API Intersection Observer v1 в самом простом случае:
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 не справляется. Давайте рассмотрим это подробнее! API Intersection Observer v1 может сообщить вам, когда элемент прокручивается в область просмотра окна, но он не сообщает вам, перекрыт ли элемент каким-либо другим содержимым страницы (то есть, когда элемент закрыт) или было ли визуальное отображение элемента изменено визуальными эффектами, такими как transform
, opacity
, filter
и т. д., которые фактически могут сделать его невидимым.
Для элемента в документе верхнего уровня эту информацию можно определить, проанализировав DOM через JavaScript, например, через DocumentOrShadowRoot.elementFromPoint()
, а затем копнув глубже. Напротив, ту же информацию нельзя получить, если рассматриваемый элемент находится в стороннем iframe.
Почему фактическая видимость имеет такое большое значение?
Интернет, к сожалению, является местом, которое привлекает плохих людей с худшими намерениями. Например, теневой издатель, который размещает рекламу с оплатой за клик на контентном сайте, может быть заинтересован в том, чтобы обманом заставить людей нажимать на его рекламу, чтобы увеличить выплату издателю за рекламу (по крайней мере, на короткий период, пока рекламная сеть не поймает их). Обычно такие объявления размещаются в iframe. Теперь, если издатель хочет, чтобы пользователи нажимали на такие объявления, он может сделать iframe рекламы полностью прозрачными, применив правило CSS iframe { opacity: 0; }
и наложив iframe поверх чего-то привлекательного, например, милого видео с котом, на которое пользователи действительно захотят нажать. Это называется clickjacking . Вы можете увидеть такую атаку clickjacking в действии в верхней части этой демонстрации (попробуйте «посмотреть» видео с котом и активировать «режим трюка»). Вы заметите, что объявление в iframe «думает», что получило законные клики, даже если оно было полностью прозрачным, когда вы (притворно-непреднамеренно) нажали на него.
Как Intersection Observer v2 решает эту проблему?
Intersection Observer v2 вводит концепцию отслеживания фактической «видимости» целевого элемента, как ее определил бы человек. При установке параметра в конструкторе IntersectionObserver
пересекающиеся экземпляры IntersectionObserverEntry
будут содержать новое логическое поле с именем isVisible
. true
значение для isVisible
является сильной гарантией базовой реализации, что целевой элемент полностью не перекрыт другим содержимым и не имеет визуальных эффектов, которые могли бы изменить или исказить его отображение на экране. Напротив, false
значение означает, что реализация не может дать такую гарантию.
Важной деталью спецификации является то, что реализация позволяет сообщать о ложных отрицательных результатах (то есть устанавливать isVisible
в false
, даже если целевой элемент полностью виден и не изменен). По соображениям производительности или по другим причинам браузеры ограничивают себя работой с ограничивающими рамками и прямолинейной геометрией; они не пытаются достичь пиксельных результатов для таких модификаций, как border-radius
.
При этом ложные срабатывания не допускаются ни при каких обстоятельствах (то есть установка isVisible
в true
, когда целевой элемент не полностью виден и не изменен).
Как новый кодекс выглядит на практике?
Конструктор IntersectionObserver
теперь принимает два дополнительных свойства конфигурации: delay
и trackVisibility
. delay
— это число, указывающее минимальную задержку в миллисекундах между уведомлениями от наблюдателя для данной цели. trackVisibility
— это логическое значение, указывающее, будет ли наблюдатель отслеживать изменения видимости цели.
Здесь важно отметить, что когда trackVisibility
имеет значение true
, delay
должна быть не менее 100
(то есть не более одного уведомления каждые 100 мс). Как отмечалось ранее, видимость требует больших затрат на расчет, и это требование является мерой предосторожности против снижения производительности и потребления заряда батареи. Ответственный разработчик будет использовать наибольшее допустимое значение для задержки.
Согласно текущей спецификации , видимость рассчитывается следующим образом:
Если атрибут
trackVisibility
наблюдателя равенfalse
, то цель считается видимой. Это соответствует текущему поведению v1.Если у цели есть эффективная матрица преобразования, отличная от двумерного переноса или пропорционального двумерного масштабирования, то цель считается невидимой.
Если цель или любой элемент в содержащей ее цепочке блоков имеет эффективную непрозрачность, отличную от 1,0, то цель считается невидимой.
Если к цели или любому элементу в содержащей ее цепочке блоков применены какие-либо фильтры, то цель считается невидимой.
Если реализация не может гарантировать, что цель полностью не будет перекрыта другим содержимым страницы, то цель считается невидимой.
Это означает, что текущие реализации довольно консервативны в плане гарантии видимости. Например, применение почти незаметного фильтра оттенков серого, например filter: grayscale(0.01%)
или установка почти невидимой прозрачности с opacity: 0.99
, сделает элемент невидимым.
Ниже приведен короткий пример кода, иллюстрирующий новые функции API. Вы можете увидеть его логику отслеживания кликов в действии во втором разделе демо (но теперь попробуйте «посмотреть» видео с щенком). Обязательно активируйте «режим трюка» снова, чтобы немедленно превратить себя в теневого издателя и увидеть, как 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'));
Ссылки по теме
- Последний редакторский черновик спецификации Intersection Observer .
- Intersection Observer v2 на платформе Chrome Статус .
- Ошибка Intersection Observer v2 Chromium .
- Blink Intent для реализации постинга .
Благодарности
Благодарим Симеона Винсента , Йоава Вайса и Матиаса Байненса за рецензирование этой статьи, а также Стефана Загера за рецензирование и реализацию функции в Chrome. Изображение главного героя от Сергея Семина на Unsplash .