Що lazy loading насправді робить із вашим Largest Contentful Paint
Lazy loading корисний, але це не універсальне виправлення продуктивності. Для LCP він може допомогти, зашкодити або не дати жодного ефекту — залежно від того, який ресурс затримується.
Зміст
- Lazy loading — це рішення про планування, а не закляття швидкості
- Що робить браузер, коли ви застосовуєте lazy load до зображення
- Просте правило: ніколи не застосовуйте lazy load до кандидата на LCP
- Виправлення: використовуйте фактичний внутрішній URL
- Коли lazy loading може покращити LCP
- Кращий шаблон для LCP-зображень
- Фонові зображення потребують додаткової уваги
- JavaScript lazy loading часто робить ситуацію гіршою
- LCP не завжди є проблемою зображень
- Як тестувати зміни lazy loading і не обманути себе
- Практична політика для більшості вебсайтів
Lazy loading — це рішення про планування, а не закляття швидкості
Lazy loading часто описують як покращення продуктивності, і це правда приблизно так само, як не пакувати валізу — це зменшення ваги. Він допомагає, бо браузер виконує менше роботи на старті.
Ця різниця важлива для Largest Contentful Paint, який зазвичай скорочують до LCP. LCP вимірює момент, коли найбільший змістовний елемент у viewport відрендерено. На багатьох сторінках таким елементом є hero image. На інших — великий заголовок, poster image, фото продукту або блок контенту.
Lazy loading змінює момент, коли ресурси запитуються. Він не змушує зображення декодуватися швидше, сервер відповідати швидше або шрифт рендеритися раніше. Якщо ви застосовуєте lazy load до неправильного елемента, особливо до того, що стає LCP, ви фактично кажете браузеру зачекати перед завантаженням саме того, що він має показати, щоб пройти Core Web Vitals.
Саме тому lazy loading і надмірно використовують, і недостатньо розуміють.
Що робить браузер, коли ви застосовуєте lazy load до зображення
Native image lazy loading зазвичай додають так:
<img src='hero.jpg' loading='lazy' alt='...'>
З loading='lazy' браузер може відкласти завантаження зображення, доки не вирішить, що воно, ймовірно, знадобиться. На практиці браузери використовують відстань до viewport, умови мережі, розміри зображення та інші евристики. Точні правила — це деталі реалізації, і вони можуть змінюватися.
З loading='eager', або здебільшого без атрибута lazy, браузер розглядає зображення як частину звичайного процесу завантаження. Йому все одно потрібно розставляти пріоритети між CSS, JavaScript, шрифтами, зображеннями та іншими запитами, але зображення стає доступним для виявлення одразу.
Це означає, що lazy loading насамперед впливає на три фази:
- Виявлення: коли браузер помічає ресурс.
- Початок запиту: коли починається мережеве завантаження.
- Час рендерингу: коли ресурс нарешті може бути декодований і намальований.
Для LCP небезпечним є початок запиту. Якщо запит LCP-зображення стартує пізно, усе після нього теж зміщується на пізніше.
Просте правило: ніколи не застосовуйте lazy load до кандидата на LCP
Якщо зображення видиме в початковому viewport і, ймовірно, є найбільшим змістовним елементом, не застосовуйте до нього lazy load.
Це стосується:
- hero images
- основних фото продукту above the fold
- великих вступних зображень у статтях
- великих зображень, схожих на фонові, але реалізованих як
<img> - video poster images, коли poster є головним візуальним елементом
Браузер не може відрендерити LCP-зображення, доки воно не буде запитане, передане, декодоване й намальоване. Lazy loading додає невизначеність перед першим кроком. Навіть невеликої затримки може бути достатньо, щоб на повільнішому з’єднанні LCP перейшов із прийнятного в поганий.
Типовий сценарій помилки виглядає так:
- Сервер надсилає HTML.
- Браузер парсить зображення above-the-fold.
- Зображення має
loading='lazy'. - Браузер чекає, бо евристика lazy-loading дозволяє йому це зробити.
- CSS і JavaScript продовжують завантажуватися.
- Запит зображення стартує пізніше, ніж мав би.
- LCP запізнюється, навіть якщо сам файл зображення достатньо оптимізований.
Це дратує, бо під час code review сторінка може виглядати охайно. Проблема не лише в розмірі файлу. Проблема в пріоритеті.
Якщо ви читаєте результати лабораторних інструментів і намагаєтеся зрозуміти, чи справді проблема в LCP, наш посібник про те, як читати звіт Lighthouse без паніки, навмисно практичний: відокремте польові дані, лабораторні підказки та виправлення, перш ніж почати змінювати код. (Примітка: якщо ваш routing чутливий до регістру, використовуйте точний URL із вашої CMS.)
Виправлення: використовуйте фактичний внутрішній URL
Правильний URL статті Wux — Як читати звіт Lighthouse без паніки. Суть лишається тією самою: визначте LCP-елемент, перш ніж змінювати поведінку завантаження.
Коли lazy loading може покращити LCP
Lazy loading може покращити LCP опосередковано, коли прибирає некритичні ресурси з дороги браузера.
Уявіть сторінку продукту з hero-зображенням продукту вгорі та каруселлю з дванадцяти рекомендаційних зображень нижче першого екрана. Якщо всі тринадцять зображень завантажуються eagerly, браузер може витрачати пропускну здатність і слоти з’єднань на зображення, яких користувач ще не бачить. На обмеженій мережі це може конкурувати з hero-зображенням, CSS або файлами шрифтів.
Lazy loading для зображень каруселі below-fold може допомогти LCP-зображенню завантажитися раніше, бо під час початкового завантаження сторінки конкурує менше некритичних запитів.
Ось легітимний сценарій продуктивності для lazy loading:
- eager load для кандидата на LCP above-the-fold
- lazy load для зображень нижче початкового viewport
- уникайте важких скриптів, які пізно вставляють важливі зображення
- зберігайте розміри зображень в HTML, щоб уникати layout shifts
Lazy loading сам по собі не є оптимізацією LCP. Це інструмент пріоритизації ресурсів. Він допомагає, коли захищає критичний шлях.
Кращий шаблон для LCP-зображень
Для LCP-зображення above-the-fold мета — зробити так, щоб браузер виявив його рано, запитав рано й відрендерив без нестабільності макета.
Надійна базова версія виглядає так:
<img
src='/images/product-hero.avif'
srcset='/images/product-hero-800.avif 800w, /images/product-hero-1400.avif 1400w'
sizes='(max-width: 768px) 100vw, 720px'
width='1400'
height='900'
loading='eager'
fetchpriority='high'
decoding='async'
alt='Black hiking backpack with roll-top closure'
>
Важливі частини тут не декоративні:
loading='eager'запобігає затримці через lazy-loading.fetchpriority='high'підказує браузеру, що це зображення важливе.widthіheightрезервують місце й зменшують layout shift.srcsetіsizesзапобігають завантаженню надто великих файлів.- Сучасний формат може скоротити час передавання, якщо використовувати його обережно.
Якщо ви досі віддаєте один великий JPEG для кожного екрана, формат зображення та responsive sizing можуть мати більше значення, ніж атрибут lazy-loading. Для практичного дерева рішень дивіться коли AVIF перемагає WebP, а коли ні.
Фонові зображення потребують додаткової уваги
CSS background images не виявляються так рано, як звичайні HTML-зображення. Браузер має завантажити й розпарсити CSS, перш ніж дізнається про них. Якщо ваш LCP-елемент — це CSS background image, ви вже ускладнили виявлення.
Це не означає, що background images заборонені. Це означає, що діяти потрібно свідомо.
Для декоративних зображень CSS backgrounds цілком підходять. Для змістовних hero-зображень елемент <img> або <picture> зазвичай кращий, бо він видимий HTML-парсеру, підтримує alt text і добре працює з атрибутами responsive image.
Якщо ви мусите використати CSS background для LCP-зображення, розгляньте preload:
<link rel='preload' as='image' href='/images/hero.avif'>
Preload — теж не чарівна паличка. Preloading надто багатьох зображень створює ту саму проблему пріоритетів, тільки в іншому костюмі. Використовуйте його для одного зображення, яке справді важливе, а не для кожного зображення в дизайн-системі.
JavaScript lazy loading часто робить ситуацію гіршою
До того як native lazy loading отримав широку підтримку, багато сайтів використовували JavaScript-бібліотеки, які підміняли data-src на src після завантаження сторінки або після спрацювання intersection observer. Деякі досі так роблять.
Це може бути доречно для довгих статей або галерей із великою кількістю зображень. Але це поганий вибір для контенту above-the-fold.
Browser preload scanner швидкий, але він не може запитати зображення, URL якого схований у custom attribute, доки не виконається JavaScript. Якщо ваше hero-зображення починається як data-src='hero.jpg', ви відклали виявлення за завантаження, парсинг, виконання скриптів і hydration фреймворку.
Це поганий компроміс для LCP. Розміщуйте URL критичних зображень у справжньому HTML. Дайте браузеру зробити свою роботу.
LCP не завжди є проблемою зображень
На деяких сторінках LCP-елементом є текст. У такому разі lazy loading зображень може мати незначний прямий вплив. Вузьким місцем може бути render-blocking CSS, повільна відповідь сервера, client-side rendering або web fonts.
Шрифти варто згадати окремо, бо вони часто є прихованою причиною пізнього рендерингу тексту. Великий заголовок може стати LCP, а поведінка завантаження шрифтів може затримати або змінити момент, коли цей заголовок буде намальовано. Якщо робота із зображеннями не рухає метрику, перевірте сам LCP-елемент напряму, а не припускайте. Наша стаття про web fonts як виграш у продуктивності описує нудні виправлення, які часто працюють: менше накреслень, сучасні формати, розумні fallback-и.
Як тестувати зміни lazy loading і не обманути себе
Не тестуйте, просто дивлячись на сторінку через офісний Wi‑Fi. Вам потрібно бачити таймінги запитів.
Використовуйте такий workflow:
- Відкрийте Chrome DevTools і запишіть Performance trace.
- Увімкніть network throttling, наприклад Fast 4G або Slow 4G.
- Перезавантажте сторінку з вимкненим кешем.
- Знайдіть LCP marker.
- Визначте LCP element.
- У Network panel перевірте, коли цей ресурс почав завантажуватися.
Якщо LCP-ресурс стартує пізно, запитайте чому:
- Чи був він lazy loaded?
- Чи його вставив JavaScript?
- Чи був він схований у CSS?
- Чи його пріоритет знизили інші зображення?
- Чи сервер відповідав повільно?
Потім внесіть одну зміну й протестуйте знову. Робота над продуктивністю стає хаотичною, коли команди змінюють формат зображень, lazy loading, preloading, JavaScript bundles і налаштування CDN в одному deployment. Ви можете покращити сторінку, але не знатимете, яка саме зміна мала значення.
Польові дані також важливі. Лабораторні інструменти корисні для діагностики, але LCP змінюється залежно від пристрою, мережі, viewport, стану кешу та географії. Використовуйте real-user monitoring або дані Chrome User Experience Report, коли можете.
<!-- tool-cta:start -->
💡 Спробуйте це: Зробіть своє LCP-зображення невеликим і таким, що завантажується з пріоритетом, обробивши його через Image Compressor, щоб воно швидко відображалося без потреби в lazy loading.
<!-- tool-cta:end -->
Практична політика для більшості вебсайтів
Для більшості маркетингових сайтів, ecommerce-сторінок, документаційних сайтів і видавничих сторінок достатньо такої політики:
- Основне зображення above-the-fold: eager load, розгляньте high fetch priority.
- Контентні зображення below-the-fold: lazy load.
- Іконки та дрібні UI assets: зазвичай не варто думати про кожен окремо.
- CSS background hero: перегляньте як HTML-зображення або обережно використайте preload.
- Hero-зображення, вставлене JavaScript: за можливості виправте rendering architecture.
- Каруселі: eager load лише для першого видимого слайда; lazy load для решти.
Існують edge cases. Евристики браузерів покращуються. Фреймворки додають автоматичні image components. Деякі платформи вже уникають lazy loading для зображень, виявлених поблизу viewport. Але принцип не змінюється: критичні ресурси мають бути ранніми й очевидними; некритичні ресурси мають чекати.
Lazy loading цінний, коли виражає цю різницю. Він шкідливий, коли ховає найважливіший контент від браузера доти, доки сторінка вже почала програвати перегони LCP.