Что lazy loading на самом деле делает с вашим Largest Contentful Paint
Lazy loading полезен, но это не универсальное исправление производительности. Для LCP он может помочь, навредить или ничего не изменить — в зависимости от того, какой ресурс откладывается.
Содержание
- Lazy loading — это решение о планировании, а не заклинание для ускорения
- Что делает браузер, когда вы лениво загружаете изображение
- Простое правило: никогда не применяйте lazy load к кандидату на LCP
- Исправление: используйте фактический внутренний URL
- Когда lazy loading может улучшить LCP
- Более правильный шаблон для изображений LCP
- Фоновым изображениям нужно дополнительное внимание
- JavaScript lazy loading часто делает ситуацию хуже
- LCP не всегда является проблемой изображений
- Как тестировать изменения lazy loading, не обманывая себя
- Практичная политика для большинства сайтов
Lazy loading — это решение о планировании, а не заклинание для ускорения
Lazy loading часто описывают как улучшение производительности, и это верно примерно в том же смысле, в каком не упакованный чемодан становится легче. Он помогает, потому что браузер выполняет меньше работы в самом начале.
Это различие важно для Largest Contentful Paint, обычно сокращаемого до LCP. LCP измеряет момент, когда в области просмотра отрисовывается самый крупный значимый элемент. На многих страницах таким элементом является hero image. На других — крупный заголовок, poster image, фотография товара или контентный блок.
Lazy loading меняет момент, когда запрашиваются ресурсы. Он не заставляет изображение декодироваться быстрее, сервер — отвечать быстрее, а шрифт — отрисовываться раньше. Если вы применяете lazy load к неправильному элементу, особенно к тому, который становится LCP, вы фактически говорите браузеру подождать перед загрузкой именно того, что он должен показать, чтобы пройти Core Web Vitals.
Именно поэтому lazy loading одновременно чрезмерно используют и недостаточно хорошо понимают.
Что делает браузер, когда вы лениво загружаете изображение
Нативный lazy loading изображений обычно добавляют так:
<img src='hero.jpg' loading='lazy' alt='...'>
С loading='lazy' браузеру разрешено отложить загрузку изображения до тех пор, пока он не решит, что изображение, вероятно, скоро понадобится. На практике браузеры учитывают расстояние до области просмотра, сетевые условия, размеры изображения и другие эвристики. Точные правила являются деталями реализации и могут меняться.
С loading='eager' или, в большинстве случаев, без атрибута lazy браузер рассматривает изображение как часть обычного процесса загрузки. Ему всё равно приходится расставлять приоритеты между CSS, JavaScript, шрифтами, изображениями и другими запросами, но изображение становится обнаруживаемым сразу.
Это означает, что lazy loading в первую очередь влияет на три фазы:
- Обнаружение: когда браузер замечает ресурс.
- Начало запроса: когда начинается сетевое получение.
- Время отрисовки: когда ресурс наконец может быть декодирован и отрисован.
Для LCP опасна фаза начала запроса. Если запрос изображения LCP начинается поздно, всё после него тоже сдвигается на более позднее время.
Простое правило: никогда не применяйте lazy load к кандидату на LCP
Если изображение видно в начальной области просмотра и, вероятно, является самым крупным contentful-элементом, не загружайте его лениво.
Это включает:
- 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 без паники, намеренно практично: разделите полевые данные, лабораторные подсказки и исправления, прежде чем менять код. (Примечание: если ваша маршрутизация чувствительна к регистру, используйте точный URL из вашей CMS.)
Исправление: используйте фактический внутренний URL
Правильный URL статьи Wux: Как читать отчёт Lighthouse без паники. Смысл остаётся тем же: определите элемент LCP, прежде чем менять поведение загрузки.
Когда lazy loading может улучшить LCP
Lazy loading может косвенно улучшить LCP, когда убирает некритичные ресурсы с пути браузера.
Представьте страницу товара с hero product image вверху и каруселью из двенадцати изображений рекомендаций ниже первого экрана. Если все тринадцать изображений загружаются eager, браузер может тратить пропускную способность и слоты соединений на изображения, которые пользователь пока не видит. В условиях ограниченной сети это может конкурировать с hero image, CSS или файлами шрифтов.
Lazy loading изображений карусели ниже первого экрана может помочь изображению LCP загрузиться раньше, потому что во время начальной загрузки страницы меньше некритичных запросов конкурируют за ресурсы.
Это законный performance-сценарий для lazy loading:
- загружайте eager кандидата на LCP above-the-fold
- применяйте lazy load к изображениям ниже начальной области просмотра
- избегайте тяжёлых скриптов, которые поздно вставляют важные изображения
- сохраняйте размеры изображений в HTML, чтобы избежать сдвигов макета
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резервируют место и уменьшают сдвиг макета.srcsetиsizesпредотвращают загрузку слишком больших файлов.- Современный формат может сократить время передачи при аккуратном использовании.
Если вы всё ещё отдаёте один большой JPEG на каждый экран, формат изображения и responsive sizing могут быть важнее, чем атрибут lazy-loading. Практическое дерево решений см. в статье когда AVIF превосходит WebP, а когда нет.
Фоновым изображениям нужно дополнительное внимание
CSS background images обнаруживаются не так рано, как обычные HTML-изображения. Браузеру нужно получить и распарсить CSS, прежде чем он узнает о них. Если ваш элемент LCP — это CSS background image, вы уже усложнили его обнаружение.
Это не значит, что фоновые изображения запрещены. Это значит, что к ним нужно подходить осознанно.
Для декоративных изображений CSS backgrounds вполне подходят. Для значимой hero-графики элемент <img> или <picture> обычно лучше, потому что он виден HTML-парсеру, поддерживает alt text и хорошо работает с атрибутами responsive images.
Если вам всё же нужно использовать CSS background для изображения LCP, рассмотрите preload:
<link rel='preload' as='image' href='/images/hero.avif'>
Preload тоже не волшебная палочка. Предзагрузка слишком большого числа изображений создаёт ту же проблему приоритетов, просто в другом костюме. Используйте её для одного изображения, которое действительно важно, а не для каждого изображения в design system.
JavaScript lazy loading часто делает ситуацию хуже
До широкой поддержки нативного lazy loading многие сайты использовали JavaScript-библиотеки, которые подставляли data-src в src после загрузки страницы или после срабатывания intersection observer. Некоторые всё ещё так делают.
Это может быть разумно для длинных статей или галерей с большим количеством изображений. Для контента above-the-fold это плохой выбор.
Сканер preload в браузере работает быстро, но он не может запросить изображение, URL которого спрятан в пользовательском атрибуте, пока не выполнится JavaScript. Если ваше hero image начинается как data-src='hero.jpg', вы отложили обнаружение до загрузки скрипта, парсинга, выполнения и гидратации фреймворка.
Это плохой компромисс для 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.
- Определите элемент LCP.
- В панели Network проверьте, когда этот ресурс начал загружаться.
Если ресурс LCP стартует поздно, спросите почему:
- Он был загружен через lazy loading?
- Он был вставлен JavaScript?
- Он был спрятан в CSS?
- Он получил более низкий приоритет из-за других изображений?
- Сервер отвечал медленно?
Затем внесите одно изменение и повторите тест. Работа над производительностью становится неразборчивой, когда команды в одном деплое меняют формат изображений, lazy loading, preloading, JavaScript-бандлы и настройки CDN. Вы можете улучшить страницу, но не узнаете, какое изменение оказалось важным.
Полевые данные тоже важны. Лабораторные инструменты полезны для диагностики, но LCP зависит от устройства, сети, области просмотра, состояния кэша и географии. Используйте real-user monitoring или данные Chrome User Experience Report, когда это возможно.
<!-- tool-cta:start -->
💡 Попробуйте это: Сделайте ваше LCP-изображение небольшим и загружаемым с приоритетом, обработав его через Image Compressor, чтобы оно быстро отображалось без необходимости lazy loading.
<!-- tool-cta:end -->
Практичная политика для большинства сайтов
Для большинства маркетинговых сайтов, ecommerce-страниц, документации и издательских страниц достаточно такой политики:
- Основное изображение above-the-fold: загружать eager, рассмотреть высокий fetch priority.
- Контентные изображения below-the-fold: загружать lazy.
- Иконки и крошечные UI-ассеты: обычно не стоят отдельного внимания.
- CSS background hero: пересмотреть в пользу HTML-изображения или аккуратно preload.
- Hero image, вставляемое JavaScript: по возможности исправить архитектуру рендеринга.
- Карусели: eager load только первый видимый слайд; остальные — lazy load.
Есть пограничные случаи. Эвристики браузеров улучшаются. Фреймворки добавляют автоматические image components. Некоторые платформы теперь избегают lazy loading для изображений, обнаруженных рядом с областью просмотра. Но принцип не меняется: критичные ресурсы должны быть ранними и очевидными; некритичные ресурсы должны ждать.
Lazy loading ценен, когда выражает это различие. Он вреден, когда скрывает самый важный контент от браузера до момента, когда страница уже начала проигрывать гонку LCP.