Intersection Observer без библиотек

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

Основная идея заключается в том, что вместо постоянной проверки позиции элемента через события scroll и вычисления getBoundingClientRect(), браузер сам уведомляет о пересечении элементов, что значительно повышает производительность.

const observer = new IntersectionObserver(callback, options);
  • callback — функция, которая вызывается каждый раз, когда наблюдаемый элемент пересекает область видимости. Она получает массив объектов IntersectionObserverEntry.
  • options — объект с настройками наблюдения.
const options = {
  root: null, // наблюдаем относительно viewport
  rootMargin: '0px', // отступы от корневого элемента
  threshold: 0.5 // процент пересечения, при котором срабатывает callback
};

threshold может быть числом от 0 до 1 или массивом чисел [0, 0.25, 0.5, 0.75, 1], определяющим на каких долях видимости элемента должен срабатывать callback.


Использование Intersection Observer для анимаций при скролле

Для реализации эффектов, аналогичных AOS, Intersection Observer позволяет запускать анимацию при появлении элемента на экране.

const elements = document.querySelectorAll('.animate-on-scroll');

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if(entry.isIntersecting){
      entry.target.classList.add('animated');
      observer.unobserve(entry.target); // Останавливаем наблюдение после анимации
    }
  });
}, { threshold: 0.1 });

elements.forEach(el => observer.observe(el));
  • .animate-on-scroll — элементы, которые должны анимироваться.
  • .animated — CSS-класс с нужной анимацией (например, через @keyframes).

Использование observer.unobserve() после срабатывания позволяет оптимизировать производительность, так как элемент больше не отслеживается.


Настройка root и rootMargin

root определяет элемент, относительно которого отслеживается видимость. Если указать null, наблюдение ведется относительно viewport.

rootMargin позволяет расширить или сузить область видимости:

const observer = new IntersectionObserver(callback, {
  root: null,
  rootMargin: '0px 0px -50px 0px', // нижний отступ
  threshold: 0.1
});

В этом примере элемент считается пересекающим область видимости, когда он приблизительно на 50px выше низа экрана.

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


Примеры CSS-анимаций

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

.animate-on-scroll {
  opacity: 0;
  transform: translateY(50px);
  transition: all 0.6s ease-out;
}

.animate-on-scroll.animated {
  opacity: 1;
  transform: translateY(0);
}

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


Множественные анимации с разными настройками

Можно создавать несколько наблюдателей для разных эффектов:

const fadeInObserver = new IntersectionObserver(callback, { threshold: 0.2 });
const slideInObserver = new IntersectionObserver(callback, { threshold: 0.5 });

document.querySelectorAll('.fade-in').forEach(el => fadeInObserver.observe(el));
document.querySelectorAll('.slide-in').forEach(el => slideInObserver.observe(el));

Каждый элемент получает индивидуальные настройки, что позволяет реализовать сложные анимационные схемы без использования сторонних библиотек.


Ленивый запуск анимаций и оптимизация

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

Расширенные возможности

  • Множественные пороги: массив threshold позволяет запускать разные стадии анимации в зависимости от степени видимости элемента.
  • Наблюдение динамически добавляемых элементов: достаточно вызвать observer.observe(newElement) после добавления элемента в DOM.
  • Событие выхода из видимости: можно обрабатывать не только появление, но и уход элемента с экрана через entry.isIntersecting === false.
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if(entry.isIntersecting){
      entry.target.classList.add('visible');
    } else {
      entry.target.classList.remove('visible');
    }
  });
}, { threshold: 0.1 });

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


Совместимость и производительность

  • Intersection Observer поддерживается во всех современных браузерах.
  • Отличается высокой производительностью по сравнению с обработчиками scroll, так как работает на уровне движка браузера и не вызывает лишние перерасчеты layout.
  • Для старых браузеров возможна полифилла, которая эмулирует поведение через события scroll, но с меньшей эффективностью.

Использование этого API позволяет создавать анимации, аналогичные AOS, полностью нативно, с минимальной зависимостью от сторонних библиотек и высокой отзывчивостью интерфейса.