1. Введение
Современные веб-страницы активно используют событие скролла для обнаружения
элементов, видимых в границах текущей области просмотра (viewport). Скроллинг
может запускать отложенную загрузку изображений и данных, анимацию элементов,
поддерживать бесконечную загрузку содержимого и многое другое. К сожалению,
событие прокрутки и расчет геометрии элементов (вызовы
Element.getBoundingClientRect()) очень ресурсоёмкие операции, выполняющиеся в
основном потоке . Это вызывает проблемы в реализации и часто приводит к снижению
производительности браузера.
Intersection Observer API был создан как решение этих проблем и новый способ
обработки событий прокрутки. Этот интерфейс предоставляет возможность наблюдать
за заданными элементами и упрощает реализацию отслеживания изменения в их
пересечении с заданным элементом-предком или самим окном просмотра (viewport),
то есть слежения за видимостью элемента.
Intersection Observer передает управление событиями
пересечения браузеру, который управляет этими событиями более эффективно,
улучшая производительность.
2. Концепция Intersection Observer
Рассмотрим несколько ключевых терминов, использующихся для определения любого экземпляра Intersection Observer.
Observer (наблюдатель, обзервер) - результат вызова класса
IntersectionObserver, его экземпляр, объект с методами.
Root (корень, контекст) - это элемент, который ожидает пересечения элемента-цели. Основа наблюдателя. По умолчанию - это окно просмотра браузера (viewport), но может использоваться любой другой элемент, если этого требует задача.
Target (цель) - элемент, за которым следит наблюдатель и оповещает о его вхождении в корень. Целью может быть любой элемент. Один наблюдатель может отслеживать множество различных целей.

При расчете пересечений, Intersection Observer рассматривает все элементы как прямоугольник, вне зависимости от их внешнего вида. Эти прямоугольники рассчитываются как наименьшие из возможных, при этом они содержат все целевое содержимое.

Можно увеличить или уменьшить размеры границ корня для расчёта пересечений. Для
этого используется rootMargin. При этом геометрия корня не меняется, изменения
касаются только расчетов границ пересечения.

3. Использование Intersection Observer
Достаточно создать новый экземпляр класса IntersectionObserver, принимающий
два аргумента — callback-функцию и объект настроек.
IntersectionObserver(callback, options)
По умолчанию, коллбэк будет вызываться, когда элемент появляется и исчезает из
области видимости. Первым аргументом коллбэк получит массив объектов
IntersectionObserverEntry, каждый из которых содержит набор свойств элемента,
показываемого в области видимости: boundingClientRect, intersectionRatio,
intersectionRect, rootBounds, target и time. Вторым аргументом в коллбек
передается ссылка на сам экземпляр обзервера.
Объект настроек позволяет задать опции с которыми будет создан обзервер. Можно
изменить контекст (root), который по умолчанию равен viewport, задать отступы
от границ контекста (rootMargin) — по умолчанию 0px. И порог вхождения
(threshold) в виде массива значений. Порог означает, сколько процентов элемента
должно попасть в область видимости для срабатывания коллбэка. Значения могут
варьироваться от 0.01 до 1.0.

Экземпляр класса - это наблюдатель, объект с набором методов, с помощью которых можно следить за DOM-элементами.
const options = {
rootMargin: '50px',
threshold: 0.5,
};
const onEntry = (entries, observer) => {
entries.forEach(entry => {
// тут можно писать логику для проверки вхождения
});
};
const observer = new IntersectionObserver(onEntry, options);
После того, как экземпляр IntersectionObserver создан, необходимо предоставить
один или несколько целевых элементов для наблюдения. Для этого на экземпляре
вызывается метод observe(elem), который принимает ссылку на DOM-элемент за
которым необходимо наблюдать. Когда элемент войдет (или выйдет) в область
видимости (root), будет вызвана callback-функция, переданная при создании
экземпляра.
const options = {
rootMargin: '50px',
threshold: 0.5,
};
const onEntry = (entries, observer) => {
entries.forEach(entry => {
// тут можно писать логику для проверки вхождения
});
};
const observer = new IntersectionObserver(onEntry, options);
observer.observe(elem);
4. Полифил Intersection Observer
Хотя Intersection Observer API поддерживается всеми последними версиями
современных браузеров, следует позаботиться о полифиле, чтобы он гарантированно
работал во всех актуальных версиях. Полифил от WICG можно взять из
этого GitHub-репозитория.
Самый простой способ добавить полифил - это использовать polyfill.io. Он загружает только указанные полифилы и только тогда, когда браузер требует этого. Это помогает свести вес страницы к минимуму, но позволяет полифилу работать без дальнейшей настройки.
Единственным недостатком полифила является то, что вы не получите преимуществ в производительности в старых браузерах, но скрипт будет работать и пользователь сможет взаимодействовать с веб-страницей.