Статья

Как оптимизировать изображения в листинге без вреда для LCP

Сергей Торкунов

В листинге нельзя загружать полноразмерное изображение карточки и уменьшать его только CSS. Сервер должен отдавать вариант под фактический размер, браузер — выбирать подходящую ширину через srcset и sizes, а изображения ниже первого экрана можно загружать лениво. Изображение, которое становится LCP, наоборот, должно быть доступно в исходном HTML и загружаться без loading="lazy".

Lazy loading сам по себе не мешает Google обнаружить картинку. Проблема возникает, когда URL изображения появляется только после прокрутки, клика или другого взаимодействия, которое поисковый робот не выполняет.

Изображения в листинге — логика работы и проверки.
Схема. Изображения в листинге — логика работы и проверки.

Почему полноразмерные изображения перегружают листинг

В текущем материале сохранён реальный пример проекта: детальная фотография товара весила около 375 КБ. При 20–30 карточках один только набор изображений мог дать примерно 9,3 МБ передачи. В другом проверенном примере — листинге «Колёса Даром» — миниатюры весили около 7 КБ, а суммарный вес листинга был около 210 КБ. Разница между исходной детальной фотографией и миниатюрой доходила примерно до 50 раз.

Эти значения нельзя превращать в универсальный бюджет. Они зависят от размеров сетки, плотности пикселей, формата, качества и количества карточек. Для публикации кейса владельцу нужно приложить дату замера, URL или обезличенный шаблон, число карточек, viewport, скрин Network и уточнить, указаны transfer size или размер ресурса.

Сначала определите роль изображения

РольЗагрузкаРазметкаЧто контролировать
Hero или первая крупная карточка, если она является LCPСразу, без lazy loadingsrc, srcset, sizes, width, height; при подтверждённом LCP — fetchpriority="high"URL есть в исходном HTML; ресурс не ждёт JS; LCP по полевым данным
Остальные изображения в первом экранеОбычно сразуАдаптивные варианты и размеры; без необоснованного fetchpriority="high"Нет конкуренции всех изображений за высокий приоритет
Карточки ниже первого экранаНативный lazy loadingloading="lazy", decoding="async", src и при необходимости srcset/sizesURL доступен без пользовательского действия
Декоративная иконкаПо ситуацииCSS или <img alt="">Не попадает в доступное имя как товарное изображение

Google рекомендует не загружать LCP-изображение лениво, а ресурс LCP должен обнаруживаться из исходного HTML. Механизм и порядок проверок разобраны в официальном руководстве по оптимизации LCP. fetchpriority="high" имеет смысл только для действительно приоритетного изображения: если назначить его всем карточкам, приоритет перестаёт помогать.

Адаптивная разметка для карточки товара

Для изображения ниже первого экрана безопасная базовая схема выглядит так:

Код: html
<picture>
  <source
    type="image/avif"
    srcset="/img/product-320.avif 320w,
            /img/product-640.avif 640w"
    sizes="(max-width: 640px) 46vw, 280px">
  <source
    type="image/webp"
    srcset="/img/product-320.webp 320w,
            /img/product-640.webp 640w"
    sizes="(max-width: 640px) 46vw, 280px">
  <img
    src="/img/product-320.jpg"
    srcset="/img/product-320.jpg 320w,
            /img/product-640.jpg 640w"
    sizes="(max-width: 640px) 46vw, 280px"
    width="640"
    height="480"
    loading="lazy"
    decoding="async"
    alt="Чёрная летняя шина — вид протектора">
</picture>

AVIF и WebP уменьшают передачу, но fallback в img src оставляет браузеру и поисковому роботу обычный URL. Значения sizes должны соответствовать реальной CSS-сетке. width и height задают пропорцию и уменьшают сдвиг макета; это не команда показывать картинку именно в таком размере.

Если первое изображение карточки подтверждено как LCP, уберите loading="lazy" и добавьте высокий приоритет только ему:

Код: html
<img
  src="/img/category-hero-1280.webp"
  srcset="/img/category-hero-640.webp 640w,
          /img/category-hero-1280.webp 1280w"
  sizes="100vw"
  width="1280"
  height="720"
  fetchpriority="high"
  decoding="async"
  alt="Летние шины в каталоге">

Две реализации lazy loading

Нативная: URL доступен до взаимодействия

Код: html
<img
  src="/img/product-320.webp"
  srcset="/img/product-320.webp 320w,
          /img/product-640.webp 640w"
  sizes="(max-width: 640px) 46vw, 280px"
  width="640"
  height="480"
  loading="lazy"
  alt="Название товара — вид спереди">

Браузер сам откладывает загрузку. URL уже есть в HTML, поэтому реализация не зависит от события пользователя.

Рискованная: URL появляется только после клика

Код: html
<img id="product-image" width="640" height="480" alt="Название товара">
<button type="button" id="show-image">Показать фото</button>

<script>
  document.querySelector('#show-image').addEventListener('click', () => {
    document.querySelector('#product-image').src = '/img/product-640.webp';
  });
</script>

В исходном HTML нет src, а без клика URL не появляется и в DOM. Google отдельно предупреждает: контент нельзя загружать только после прокрутки или клика, потому что робот может не выполнить такое взаимодействие. Исправление — отдать src/srcset сразу и использовать нативный loading="lazy" либо IntersectionObserver как улучшение, а не как единственный способ сформировать URL.

Три обязательные проверки

Исходный HTML. Откройте View Source или ответ сервера в DevTools. У каждой индексируемой карточки должен быть реальный img src; адаптивные варианты — в srcset. data-src без src требует отдельного обоснования и проверки.

Отрендеренный DOM. В DevTools Elements и URL Inspection проверьте, что после выполнения JS у изображения сохраняются ожидаемый URL, alt, размеры и контекст карточки. Контент не должен появляться только после клика.

Прямой URL изображения. Откройте выбранный ресурс: ответ 200, корректный Content-Type, без авторизации и блокирующего robots.txt. Проверьте, что CDN не отдаёт HTML-заглушку вместо файла.

Рекомендации и примеры механизма опубликованы в документации Google по lazy loading и руководстве по изображениям в Google Search.

Как задать бюджет и воспроизвести замер

Бюджет считайте из шаблона, а не из средней цифры по рынку:

бюджет изображений первого экрана = число реально видимых изображений × целевой transfer size одного варианта.

Затем проверьте, какой вариант браузер выбрал при каждом viewport и DPR. Если карточка отображается шириной 280 CSS-пикселей на экране с DPR 2, браузеру может понадобиться вариант около 560 физических пикселей; точный выбор зависит от sizes и набора кандидатов.

Порядок замера:

Зафиксируйте URL, дату, commit/release, viewport, DPR, сеть и число карточек.

В DevTools Network включите Disable cache, отфильтруйте Img, перезагрузите страницу и сохраните HAR/скрин. Запишите transfer size, фактически выбранный URL и dimensions.

Запустите Lighthouse в одинаковом профиле до и после. Это лабораторная проверка, а не замена полевым данным.

В PageSpeed Insights проверьте полевые Core Web Vitals, если для URL или origin достаточно данных. В документации Core Web Vitals Google считает хорошим LCP на 75-м процентиле не более 2,5 секунды; сравнивайте одинаковый тип устройства и окно данных.

Проверьте визуальное качество на 1× и 2×, масштабирование, ошибки 404 и CLS. Экономия байтов не принимается, если товар невозможно рассмотреть.

Нормальный результат: браузер не скачивает детальные оригиналы для миниатюр, LCP-ресурс обнаруживается рано, изображения ниже первого экрана откладываются, пропорции зарезервированы, а качество остаётся приемлемым. Ошибка: все картинки получают fetchpriority="high", LCP лениво загружается, sizes всегда равен 100vw для узкой карточки или URL существует только в обработчике клика.

Где заканчивается задача изображений

Оптимизация изображений не решает правила создания фильтров и индексирования URL. Для этого нужен отдельный технический слой — как внедрить умный SEO-фильтр. Если проблема начинается с дерева категорий и путей пользователей, сначала проверьте структуру интернет-магазина для SEO, а затем настраивайте медиаварианты внутри утверждённого шаблона.

Получите бесплатный аудит и стратегию роста

Изучим сайт, покажем точки роста и подготовим прогноз до квалифицированных лидов и оборота из SEO/GEO.