Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «IntersectionObserver». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`IntersectionObserver` це вбудований API браузера, який стежить за елементом і повідомляє, коли той потрапляє в область видимості (viewport) або виходить з неї, без важких обробників `scroll`.** Спостерігач створюється через `new IntersectionObserver(callback, options)`, де `root` задає контейнер, `rootMargin` відступи, а `threshold` частку видимості для спрацювання. У колбек приходить масив `IntersectionObserverEntry` з полями `isIntersecting`, `intersectionRatio`, `target`. Типові сценарії: lazy loading зображень, анімації появи при скролі, аналітика переглядів. ```javascript const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) entry.target.classList.add('visible'); }); }); observer.observe(document.querySelector('#target')); ``` **Ключове:** це «спостерігач за видимістю», який замінює `onscroll` і `getBoundingClientRect()` і працює асинхронно, майже без навантаження на CPU.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`IntersectionObserver` це вбудований API браузера, який дозволяє відстежувати, коли елемент потрапляє в область видимості (viewport) або виходить із неї, без важких обробників `scroll`.** Це об'єкт, який «спостерігає» за елементом і повідомляє, коли той перетинається з областю перегляду або з іншим контейнером. ## Теорія ### TL;DR - `IntersectionObserver` стежить за перетином елемента з viewport або з заданим контейнером. - Це заміна `scroll`-подіям, ручним перевіркам `getBoundingClientRect()` і `window.onscroll`. - Створення: `new IntersectionObserver(callback, options)` плюс `observer.observe(element)`. - Опції: `root`, `rootMargin`, `threshold`. - У колбек приходить масив `IntersectionObserverEntry` з `isIntersecting`, `intersectionRatio`, `target`. - Зупинка: `observer.unobserve(target)` для одного елемента, `observer.disconnect()` для всіх. ### Швидкий приклад ```javascript const target = document.querySelector('#target'); const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { console.log('Елемент з\'явився в зоні видимості!'); } else { console.log('Елемент вийшов із зони видимості!'); } }); }); observer.observe(target); // починаємо спостерігати ``` ### Простий приклад на сторінці ```html <div style="height: 120vh;"></div> <div id="target" style="height: 100px; background: coral;">Я ціль</div> <div style="height: 120vh;"></div> <script> const target = document.querySelector('#target'); const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { console.log('Елемент з\'явився в зоні видимості!'); } else { console.log('Елемент вийшов із зони видимості!'); } }); }); observer.observe(target); // починаємо спостерігати </script> ``` Коли ви прокрутите сторінку і блок потрапить на екран, у консоль виведеться: ```text Елемент з'явився в зоні видимості! ``` Це чудова альтернатива: - подіям `scroll`; - ручним перевіркам через `getBoundingClientRect()`; - обробникам `window.onscroll`, які сильно навантажують сторінку. ### Параметри конструктора ```javascript new IntersectionObserver(callback, options); ``` | Параметр | Що робить | | --- | --- | | `callback` | Функція, яку викликають при кожному перетині | | `options.root` | Контейнер, усередині якого відстежувати (за замовчуванням вікно браузера) | | `options.rootMargin` | Відступи (наприклад `'0px 0px -100px 0px'`), як у CSS `margin` | | `options.threshold` | Поріг спрацювання, частка видимості елемента (від 0 до 1) | Приклад з налаштуваннями: ```javascript const observer = new IntersectionObserver(callback, { root: null, // вікно браузера rootMargin: '0px 0px -100px 0px', // спрацює трохи раніше threshold: 0.5 // коли видно 50% елемента }); ``` ### Об'єкт entry у колбеку Кожен елемент, за яким стежить спостерігач, представлений об'єктом `IntersectionObserverEntry`: ```javascript entry.isIntersecting; // true / false entry.intersectionRatio; // частка видимої частини (від 0 до 1) entry.boundingClientRect; // положення елемента entry.rootBounds; // межі області видимості entry.target; // сам елемент ``` Колбек отримує саме масив таких записів, бо один спостерігач може стежити за сотнями елементів, і за один тік браузер віддає всі зміни разом. ### Практичні приклади Ліниве з'явлення елементів: ```javascript const items = document.querySelectorAll('.fade'); const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } }); }); items.forEach((item) => observer.observe(item)); ``` ```css .fade { opacity: 0; transform: translateY(20px); transition: 0.5s; } .fade.visible { opacity: 1; transform: translateY(0); } ``` Елементи плавно «випливають», коли потрапляють на екран. Лінива загрузка зображень: ```html <img data-src="photo.jpg" alt="photo" width="400" height="300" /> ``` ```javascript const images = document.querySelectorAll('img[data-src]'); const observer = new IntersectionObserver((entries, obs) => { entries.forEach((entry) => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; obs.unobserve(img); // перестаємо стежити за цією картинкою } }); }); images.forEach((img) => observer.observe(img)); ``` Тепер зображення завантажуються **тільки тоді, коли стають видимими**, а це економить трафік і пришвидшує завантаження сайту. ### Переваги над scroll і керування спостереженням | Звичайний scroll | IntersectionObserver | | --- | --- | | Викликає подію на **кожному пікселі** прокрутки | Працює асинхронно та ефективно | | Треба вручну рахувати `getBoundingClientRect()` | Усе рахує сам | | Навантаження на CPU | Майже нульове навантаження | | Незручно з великою кількістю елементів | Один спостерігач стежить за сотнями елементів | Щоб перестати стежити за конкретним елементом: ```javascript observer.unobserve(target); ``` Щоб повністю вимкнути спостерігач: ```javascript observer.disconnect(); ``` Підсумок: | Що робить | `IntersectionObserver` | | --- | --- | | Відстежує | Коли елемент входить в область видимості або виходить з неї | | Замінює | `onscroll` і `getBoundingClientRect()` | | Використовується для | Лінивого завантаження, анімацій при скролі, аналітики переглядів | | Продуктивність | Дуже висока, розрахунки робить браузер, а не ваш JS-код | > **Запам'ятайте просто:** `IntersectionObserver` це «спостерігач за видимістю». Він повідомляє, коли елемент з'явився на екрані, і робить це ефективно, без зайвих подій `scroll`. ### Типові помилки - Забувати викликати `observer.observe(element)`. Створений спостерігач сам по собі ні за чим не стежить. - Чекати, що колбек спрацює лише при появі елемента. Він викликається і при виході з видимості, тому перевірка `entry.isIntersecting` обов'язкова. - Не викликати `unobserve()` після одноразової дії (наприклад підвантаження картинки) і виконувати роботу знову при кожному перетині. - Плутати `threshold: 0` і `threshold: 1`: перший спрацьовує на першому пікселі елемента, другий лише коли видно весь елемент. - Задавати `rootMargin` у відсотках там, де потрібні пікселі, або взагалі без одиниць. Значення без одиниць браузер відхилить. - Використовувати `root` з елементом, який не є предком цілі. Спостереження тоді не працює так, як очікується. - Не відключати спостерігач при знищенні компонента (`disconnect()`), через що лишаються витоки пам'яті і колбеки для вже видалених вузлів.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.