Веб-производительность
LCP: как оптимизировать Largest Contentful Paint

LCP — главный показатель скорости загрузки в [Core Web Vitals](/glossary/core-web-vitals). Он измеряет, как быстро пользователь видит основной контент страницы. Разбираем: что влияет на LCP, почему он тормозит, и как довести его до зелёного порога в реальных проектах.
Largest Contentful Paint (LCP) — метрика Core Web Vitals, которая с 2021 года влияет на ранжирование в Google. Это не просто технический показатель: он отражает реальное восприятие загрузки страницы пользователем. Плохой LCP — это когда посетитель видит пустой экран или незагруженную шапку и уходит, не дождавшись контента.
Что такое LCP и зачем его оптимизировать
LCP измеряет время от начала навигации до момента, когда наибольший по площади контентный элемент (текст или изображение) становится видимым в области просмотра (viewport). Это пороговое значение, за которым Google считает загрузку «завершённой» с точки зрения пользовательского опыта.
В отличие от FCP (First Contentful Paint), который фиксирует момент появления первого пикселя, LCP отслеживает именно значимый контент. Страница может показать спиннер через 0.3 сек, но если главное изображение появится через 5 сек — LCP будет 5 сек.
Хороший LCP
Зелёный порог Google. Цель для большинства страниц
Требует улучшения
Жёлтая зона — LCP заметен пользователю, нужна оптимизация
Плохой LCP
Красная зона — значительный ущерб для UX и ранжирования
Порог CrUX
Google оценивает LCP сайта по 75-му перцентилю реальных пользователей
Какие элементы браузер считает LCP-кандидатами
Браузер не отслеживает любой элемент страницы — он смотрит только на конкретные типы и выбирает наибольший по площади в viewport на момент завершения загрузки.
- <img> элементы
- Стандартные изображения. Самый частый LCP-кандидат на большинстве страниц. Время = момент появления декодированного изображения в viewport.
- <image> в SVG
- Изображения внутри SVG-элементов. Обрабатываются как обычные img с точки зрения LCP.
- CSS background-image
- Фоновые изображения через CSS. Важный нюанс: браузер не начинает загружать background-image до тех пор, пока не построит CSSOM. Это один из главных источников задержки LCP.
- Блоки с текстом
- Элементы <p>, <h1>–<h6>, <div> и другие с текстовым содержимым. Если текстовый блок крупнее изображения — именно он становится LCP.
- <video> с poster
- Постер видеоэлемента (атрибут poster). Если видео занимает большую часть экрана, poster должен загружаться максимально быстро.
Из чего складывается время LCP
Google разбивает LCP на 4 подкомпоненты. Понимание каждого из них — ключ к правильной диагностике и приоритизации оптимизаций.
| Компонент | Что измеряет | Типичная доля |
|---|---|---|
| TTFB (Time to First Byte) | Время до получения первого байта HTML от сервера | 10–40% |
| Resource Load Delay | Задержка между TTFB и началом загрузки LCP-ресурса | 10–30% |
| Resource Load Duration | Время загрузки самого LCP-ресурса (изображения, шрифта) | 30–60% |
| Element Render Delay | Задержка между загрузкой ресурса и его появлением в viewport | 0–20% |
Правило: атакуйте компонент с наибольшей долей. Если TTFB занимает 3 из 5 секунд LCP — оптимизация изображений даст минимальный эффект. Сначала нужно улучшить серверный ответ.
Главные причины медленного LCP
90% плохих LCP объясняются одними и теми же причинами. Диагностика занимает 15 минут в DevTools или PageSpeed Insights.
Медленный TTFB
Сервер отвечает дольше 600 мс. Причины: нет кэширования, слабый хостинг, тяжёлые запросы к БД, отсутствие CDN. При TTFB > 800 мс достичь LCP < 2.5 сек почти невозможно без прочих оптимизаций.
Неоптимизированные изображения
LCP-изображение весит 500 KB+ в JPEG вместо 80 KB в WebP/AVIF. Нет атрибута fetchpriority="high", нет preload. Браузер обнаруживает изображение поздно и загружает медленно.
Render-blocking ресурсы
CSS и JS в <head> без async/defer блокируют рендеринг. Пока браузер не загрузит и не выполнит их — LCP-элемент не появится. Каждый лишний скрипт в head добавляет задержку.
Медленная загрузка шрифтов
Если LCP — текстовый блок, а шрифт загружается 2+ сек, браузер показывает FOIT (невидимый текст) или FOUT (системный шрифт). Время до появления правильного текста = LCP.
Lazy load на LCP-элементе
Атрибут loading="lazy" на главном изображении hero-секции — одна из самых частых ошибок. Браузер намеренно откладывает загрузку, а это прямой удар по LCP.
LCP в клиентском рендеринге
В SPA (React, Vue, Angular) контент генерируется в браузере через JavaScript. Браузер видит пустой HTML → загружает JS → рендерит контент. Весь этот процесс суммируется в LCP.
Как оптимизировать LCP: пошаговый план
Оптимизация LCP — это не один трюк, а набор взаимосвязанных улучшений. Работайте последовательно от самых высокодоходных.
Шаг 1: Снизить TTFB до 200–400 мс
TTFB — фундамент. Если сервер отвечает медленно, все остальные оптимизации работают «поверх» этого потолка.
- Настройте HTTP-кэширование: Cache-Control: max-age=31536000 для статики, s-maxage для CDN-прокси.
- Включите сжатие: Brotli (приоритет) или gzip для HTML, CSS, JS. Brotli даёт на 15–25% меньший размер, чем gzip.
- Подключите CDN: Cloudflare, Fastly, BunnyCDN. Для статичных сайтов — edge caching снижает TTFB до 20–50 мс.
- Оптимизируйте базу данных: индексы на часто используемых полях, кэш запросов через Redis/Memcached.
- Используйте HTTP/2 или HTTP/3: множественные запросы по одному соединению без head-of-line blocking.
Шаг 2: Оптимизировать LCP-изображение
Если LCP-элемент — изображение (hero, product image), это дерево оптимизаций с высоким ROI.
- Конвертируйте в современные форматы: WebP (экономия 25–35% vs JPEG) или AVIF (40–55% vs JPEG). Используйте <picture> с fallback.
- Добавьте атрибут fetchpriority="high" на LCP-изображение — браузер загрузит его в первую очередь.
- Уберите loading="lazy" с LCP-элемента. Lazy load уместен только для изображений ниже first viewport.
- Добавьте <link rel="preload" as="image"> в <head> для LCP-изображения — браузер начнёт загрузку до парсинга body.
- Укажите атрибуты width и height для предотвращения CLS. Браузер зарезервирует место до загрузки изображения.
- Настройте srcset и sizes для адаптивной загрузки: мобиль получит изображение 400 px вместо 1600 px.
Шаг 3: Устранить render-blocking ресурсы
Каждый ресурс, который блокирует рендеринг, добавляет задержку к LCP. Цель — ни одного блокирующего ресурса в критическом пути.
| Тип ресурса | Проблема | Решение |
|---|---|---|
| JavaScript в <head> | Браузер останавливает парсинг HTML и выполняет скрипт | defer или async на всех не-критических скриптах |
| CSS в <head> | Браузер не рендерит ничего до загрузки всего CSS | Critical CSS inline + async loadCSS для некритичного |
| Сторонние скрипты | Аналитика, чат-боты, пиксели загружаются в head | Перенести в body или загружать с задержкой (setTimeout 3000) |
| Шрифты без preload | Браузер обнаруживает шрифт только после парсинга CSS | <link rel="preload" as="font"> + font-display: swap |
Шаг 4: Оптимизировать шрифты (если LCP — текст)
Когда LCP-элемент — текстовый блок (заголовок, лид), проблема может быть в задержке отрисовки шрифта.
- Добавьте font-display: swap или optional в @font-face. Браузер покажет системный шрифт немедленно и заменит на кастомный после загрузки.
- Используйте <link rel="preload" as="font" type="font/woff2" crossorigin> для критичных шрифтов в <head>.
- Ограничьте набор символов: используйте subsetting для загрузки только нужных символов (латиница, кириллица).
- Self-host шрифты вместо загрузки с Google Fonts — убираете дополнительный DNS-lookup и соединение.
- Настройте size-adjust, ascent-override, descent-override в @font-face для уменьшения CLS при подмене шрифта.
Шаг 5: SSR/SSG для JavaScript-фреймворков
Если сайт на React, Vue или Next.js без SSR — LCP будет высоким по умолчанию: браузер должен загрузить, выполнить JavaScript и только потом отрендерить контент.
- Server-Side Rendering (SSR)
- HTML генерируется на сервере при каждом запросе. Браузер получает готовый HTML, парсит его и LCP-элемент появляется без ожидания JS. Лучший вариант для динамического контента.
- Static Site Generation (SSG)
- HTML генерируется на этапе сборки. Сервер отдаёт готовый файл — максимально быстрый TTFB и LCP. Идеал для блогов, лендингов, страниц без персонализации.
- Incremental Static Regeneration (ISR)
- SSG с периодической регенерацией (Next.js). Сочетает скорость статики с актуальностью данных. Оптимален для большинства CMS-контента.
- Streaming SSR
- Сервер начинает отправлять HTML до завершения рендеринга — браузер прогрессивно отображает контент. React 18 + Next.js 13+ поддерживают out of the box.
Шаг 6: CSS background-image как LCP
Если LCP-элемент использует background-image через CSS — браузер не начнёт его загрузку до построения CSSOM. Это одна из самых коварных причин медленного LCP.
- Замените CSS background-image на <img> с fetchpriority="high" — браузер обнаружит его на этапе HTML-парсинга.
- Если замена невозможна — используйте <link rel="preload" as="image"> для ручного запуска загрузки.
- Для адаптивных фонов используйте imagesrcset и imagesizes в preload-теге.
- Переместите CSS, содержащий LCP background-image, в inline <style> — убирает один сетевой запрос.
Инструменты для измерения и диагностики LCP
Правильная диагностика важнее оптимизации вслепую. Используйте оба типа инструментов: Lab (синтетические тесты) и Field (реальные пользователи).
| Инструмент | Тип данных | Что даёт | Когда использовать |
|---|---|---|---|
| PageSpeed Insights | Lab + Field (CrUX) | Оценка LCP, разбивка по подкомпонентам, конкретные рекомендации | Первичный аудит, проверка изменений |
| Chrome DevTools Performance | Lab | Waterfall загрузки, точная причина задержки LCP, flame chart | Глубокая диагностика конкретной проблемы |
| Lighthouse CI | Lab | Автоматизированные проверки в CI/CD, история LCP по релизам | Регрессионный контроль |
| WebPageTest | Lab | Тест из разных регионов, видео сравнение, filmstrip, waterfall | Проверка CDN, регионального LCP |
| Google Search Console (CWV) | Field (CrUX) | Реальный LCP по группам URL, URL с проблемами | Мониторинг в продакшне |
| web-vitals.js | Field | JavaScript API для сбора LCP у реальных пользователей в свою аналитику | Custom мониторинг, RUM |
Как диагностировать LCP в Chrome DevTools
DevTools — самый точный инструмент для понимания, что именно тормозит LCP на конкретной странице.
- Откройте DevTools → Performance → нажмите Record, перезагрузите страницу, остановите запись.
- В Timings найдите маркер LCP — он показывает точное время и элемент.
- Изучите Waterfall: найдите ресурс LCP-элемента и проверьте, когда началась его загрузка относительно TTFB.
- Обратите внимание на красные полосы — это render-blocking ресурсы. Они прямо перед LCP.
- Вкладка Network → Filter по типу Image — найдите LCP-изображение, проверьте приоритет (должен быть High).
- Coverage вкладка — показывает неиспользуемый CSS/JS. Большой объём неиспользуемого кода = задержка LCP.