Что наблюдает Intersection Observer для ленивой загрузки
Что проверяют
Знаете ли вы, что именно наблюдает этот интерфейс, и понимаете ли, почему он дешевле обработчика прокрутки. Ответ «следит за видимостью элемента» проходит только до первого уточняющего вопроса.
Как отвечать
Наблюдается пересечение прямоугольника целевого элемента с прямоугольником корня. Корень это видимая область окна по умолчанию или заданный предок со скроллом, раздвинутый на rootMargin. Колбэк вызывается, когда доля пересечения переходит одно из значений threshold, и один раз сразу после observe, чтобы сообщить начальное состояние.
Пересечение считает сам браузер и асинхронно, поэтому нет принудительного пересчёта макета, который даёт связка прокрутки и getBoundingClientRect.
В колбэк приходят записи с полями isIntersecting, intersectionRatio, boundingClientRect, intersectionRect, rootBounds и target.
Для ленивой загрузки схема простая: подставить настоящий адрес при первом пересечении и сразу отписаться, а запас по rootMargin дать такой, чтобы картинка успела загрузиться до кадра.
const io = new IntersectionObserver((entries, obs) => {
for (const e of entries) {
if (!e.isIntersecting) continue;
e.target.src = e.target.dataset.src;
obs.unobserve(e.target);
}
}, { rootMargin: "200px 0px", threshold: 0 });Стоит добавить, что для картинок обычно хватает атрибута loading="lazy", а наблюдатель нужен под свою логику: догрузка списка, анимация появления, счётчик просмотров.
Где спотыкаются
Считают, что отслеживается видимость. Проверка чисто геометрическая: элемент, перекрытый другим блоком или прозрачный, всё равно считается пересекающимся, а скрытый через display: none просто даёт нулевой прямоугольник и не сработает никогда.
Второе: не резервируют место под содержимое. Пока картинки не загружены, высота контейнеров нулевая, все они одновременно попадают в кадр, и ленивая загрузка превращается в обычную. Спасают заданные размеры или aspect-ratio.
Третье: указывают корнем элемент, который не является предком цели, и молча не получают ни одного срабатывания. Рядом забытые unobserve и disconnect: наблюдатель продолжает держать ссылки на уже удалённые узлы.