Intersection Observer API

Intersection Observer API позволяет отслеживать пересечение одного элемента с другим или с областью видимости браузера, что делает возможным эффективное управление ленивой загрузкой контента, анимациями при прокрутке и оптимизацией производительности. Основная идея заключается в том, чтобы наблюдать за элементом и получать уведомления при его появлении или исчезновении из видимой области.

API работает через объект IntersectionObserver, который создается с помощью конструктора:

const observer = new IntersectionObserver(callback, options);
  • callback — функция, вызываемая каждый раз, когда наблюдаемый элемент пересекает границы контейнера или области видимости.
  • options — объект с настройками поведения наблюдателя.

Параметры options

const options = {
  root: null,            // Элемент-контейнер, относительно которого проверяется видимость. null = viewport.
  rootMargin: '0px',     // Отступы вокруг root, можно использовать px или %.
  threshold: 0           // Процент видимости элемента для срабатывания callback (0–1 или массив).
};
  • root — родительский элемент для отслеживания. Если null, то отслеживание ведется относительно окна браузера.
  • rootMargin — позволяет расширять или сужать область наблюдения, например '0px 0px -100px 0px' сдвигает нижнюю границу вверх на 100 пикселей.
  • threshold — указывает, при каком проценте видимости элемента вызывается callback. Может быть числом или массивом чисел, что позволяет получать уведомления при нескольких стадиях видимости.

Callback функция

Callback получает два аргумента:

  1. entries — массив объектов IntersectionObserverEntry.
  2. observer — ссылка на сам наблюдатель.

Объект IntersectionObserverEntry содержит ключевые свойства:

  • target — элемент, за которым ведется наблюдение.
  • isIntersecting — булевое значение, указывающее, пересек ли элемент наблюдаемую область.
  • intersectionRatio — процент видимой части элемента (от 0 до 1).
  • boundingClientRect — размеры и позиция элемента.
  • intersectionRect — пересекающаяся часть элемента с областью root.

Пример базового использования:

const callback = (entries, observer) => {
  entries.forEach(entry => {
    if(entry.isIntersecting) {
      entry.target.classList.add('visible');
      observer.unobserve(entry.target); // прекращает наблюдение
    }
  });
};

const observer = new IntersectionObserver(callback, { threshold: 0.5 });
document.querySelectorAll('.animate').forEach(el => observer.observe(el));

Ленивая загрузка изображений

Intersection Observer идеально подходит для отложенной загрузки изображений. Вместо того чтобы грузить все изображения сразу, их можно загружать по мере появления в зоне видимости:

const images = document.querySelectorAll('img[data-src]');

const loadImage = (entry) => {
  const img = entry.target;
  img.src = img.dataset.src;
  img.removeAttribute('data-src');
};

const imgObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if(entry.isIntersecting) {
      loadImage(entry);
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.1 });

images.forEach(img => imgObserver.observe(img));

Анимации при скролле

Для создания эффектов появления или прокрутки можно добавлять классы при пересечении элементов с viewport:

const sections = document.querySelectorAll('.section');

const revealSection = (entries, observer) => {
  entries.forEach(entry => {
    if(entry.isIntersecting) {
      entry.target.classList.add('reveal');
      observer.unobserve(entry.target);
    }
  });
};

const sectionObserver = new IntersectionObserver(revealSection, { threshold: 0.2 });
sections.forEach(section => sectionObserver.observe(section));

Такой подход уменьшает нагрузку на браузер, так как анимации запускаются только для видимых элементов.

Особенности и оптимизация

  • Пакетная обработка: callback вызывается один раз для всех элементов, чьи состояния изменились за один кадр, что повышает производительность.
  • Поддержка rootMargin и threshold позволяет гибко настраивать момент срабатывания, например, запуск анимаций до полного появления элемента.
  • Отмена наблюдения: метод unobserve(target) прекращает наблюдение за конкретным элементом, что уменьшает расход ресурсов.
  • Полная остановка: метод disconnect() прекращает наблюдение за всеми элементами.

Ограничения

  • Intersection Observer не поддерживается в очень старых браузерах, поэтому для них может потребоваться полифил.
  • Наблюдение за большим количеством элементов без оптимизации может увеличивать нагрузку, поэтому рекомендуется использовать unobserve после достижения цели.

Совмещение с Smooth Scroll

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