Довольно многие, кто близок к миру web разработки, не раз слышали про метрики web-vitals. По-настоящему значимыми они стали в середине 2021 года — в этот период Google официально стал учитывать метрики в ранжировании для мобильного поиска. С тех пор многие компании стремятся добиться хороших показателей метрик web-vitals. И, пожалуй, самая важная из этих метрик — LCP.
Привет! Меня зовут Николай, я — frontend-разработчик в компании Иви. В зоне моей ответственности как раз и лежит web-версия онлайн-кинотеатра. И в четвертом квартале 2025 года команда web решила сосредоточить ресурсы на метрике LCP. Что такое web-vitals в целом и LCP в частности?
Оглавление
Метрики web-vitals — что это?
Web-vitals — это инициатива Google, которая выделяет ключевые метрики для оценки пользовательского опыта на сайте. Если раньше были десятки сложных показателей, то web-vitals фокусируется на нескольких, самых важных.
Цель — дать единый, понятный язык для разработчиков, SEO-специалистов и руководителей, чтобы оценить, насколько быстро, отзывчиво и стабильно работает сайт для реальных пользователей.
Текущие ключевые метрики web-vitals
Ключевая тройка метрик меняется каждые несколько лет. Сейчас (2026) это:
LCP (Largest Contentful Paint) — «Как быстро загружается основное содержимое?» (Метрика загрузки)
INP (Interaction to Next Paint) — «Как быстро сайт реагирует на клики, тапы, нажатия клавиш?» (Метрика отзывчивости). (Примечание: заменил FID в 2024 году)
CLS (Cumulative Layout Shift) — «Насколько стабильно отображается страница, не "прыгает" ли контент?» (Метрика визуальной стабильности)
Почему им уделяют столько внимания?
Пользовательский опыт: Прямая связь с удовлетворенностью
SEO: Являются ранжирующим фактором в поиске Google
Бизнес-метрики: Хорошие web-vitals коррелируют с более высокой конверсией и вовлеченностью
Подробнее про метрику LCP
Простыми словами: LCP измеряет, через какое время самый большой и заметный элемент в видимой области экрана (viewport) становится полностью отрисованным. Это момент, когда пользователь видит, что «страница уже грузится» и появляется главный контент.
Что считается LCP-элементом?
Изображения (
<img>,<image>внутри<svg>)Постер-изображения внутри видео (
<video>сposter)Элементы с фоновым изображением, загруженным через
url()(css свойство background-image)Блочные элементы (
<div>,<p>,<h1>) с текстовым узлом
Примеры с сайта Иви:
для главной страницы LCP-элементом является постер в слайдере:

для доступного контента LCP-элементом является постер в плеере:

пример, где LCP-элементом является текстовый узел (заголовок страницы):

Что НЕ считается LCP-элементом?
Элементы, которые находятся за пределами видимой области
Слишком мелкие элементы — выбирается всегда самый большой
Анимированные или меняющиеся элементы
Пороги оценки LCP:
Хорошо (Good): ≤ 2.5 секунды
Требует улучшений (Needs Improvement): 2.5 – 4.0 секунды
Плохо (Poor): > 4.0 секунды
Инструменты для мониторинга LCP
Основным инструментом для мониторинга web-vitals метрик являются так называемые CrUX (Chrome User Experience) отчеты, которые строит Google. Эти отчеты находятся в открытом доступе и можно смотреть состояние метрик в принципе для любого сайта. Вот ссылка-пример такого отчета для сайта Иви:
В качестве упражнения, попробуйте посмотреть CrUX отчеты ваших любимых сервисов.

Тут можно обратить внимание на вкладку Controls — она позволяет гибко настраивать вывод графика метрик. Чем именно пользуется наша команда:
В фильтре Data мы глобально ориентируемся на Origin — данное значение показывает LCP для всех страниц сайта в целом
В фильтре Device — в первую очередь ориентируемся на мобильные устройства (Phone)
И также нас интересует 75 перцентиль — это показатель, сколько страниц сайта имеют определенное значение метрики
Решение сосредоточить силы команды было принято исходя как раз из этого отчета, и основной нашей задачей было улучшить LCP для мобильных устройств, потому что значение метрики «подбиралось» к желтой зоне (>2.5 секунд). Почему также не десктоп? А для десктопа у нас значение метрики было с хорошим запасом (по данным CrUX отчетов в районе ~1800ms):

И еще одной причиной внимания именно к мобильным значениям метрики является инициатива Google, называемая mobile-first-indexing. Это подход, при котором для сканирования, индексации и ранжирования сайтов используется в первую очередь их мобильная версия, а не десктопная. Это означает, что контент, структура и технические параметры (скорость, адаптивность), доступные на смартфонах, определяют место сайта в поисковой выдаче. Подробнее тут — https://developers.google.com/search/docs/crawling-indexing/mobile/mobile-sites-mobile-first-indexing?hl=ru
Препарируем метрику LCP — из чего она состоит?
Для дальнейшего понимания и поиска узких мест надо разобраться, из чего же состоит метрика LCP и что именно показывают ее составляющие:
Метрику LCP составляют четыре «подметрики» в порядке их подсчета при загрузке страницы с LCP-элементом:
TTFB — Time to first byte — время от начала навигации до получения первого байта HTML-документа от сервера. Эта метрика показывает скорость работы бэкенда и сети. Важно отметить, что эта метрика также считается отдельной самостоятельной метрикой web-vitals, но при этом входит в конечный LCP
Resource Load Delay — задержка начала загрузки LCP-элемента. Это время между TTFB и моментом, когда браузер фактически начал скачивание LCP-элемента. Большая задержка означает, что более важный ресурс ждал, пока скачаются менее важные
Resource Load Duration — собственно время скачивания LCP-элемента. Тут все просто. На значение этой метрики влияет размер изображения, его степень сжатия, скорость работы сети и наличие кэша
Element Render Delay — это время между окончанием загрузки элемента и его финальной отрисовки на экране. На эту метрику может влиять опять же размер изображения (от этого зависит скорость его декодирования на CPU, особенно для более слабых по сравнению с ПК мобильных устройств); ожидание основного потока (Main Thread); ожидание стилей
Очень удобно, что CrUX отчет также предоставляет графики этих составляющих LCP, где можно отдельно проанализировать изменение в течение времени каждой из них:

Анализ и выявление возможностей для оптимизации
Сейчас по логике я должен рассказать, как мы проводили анализ и выявляли куда двигаться, но я сделаю небольшое отступление. Параллельно с тем, что команда взяла задачу по улучшению метрики, один из наших коллег решил сделать эксперимент. Исторически сложилось так, что картинки на сайте Иви в большинстве своем были в формате JPEG, тем временем как формат WebP уже обзавелся внушительной поддержкой современными браузерами. Было принято решение провести эксперимент с заменой формата с JPEG на WebP. Для замеров использовался стенд — пустая страница с одним вариантом картинки из двух: A) JPEG B) WebP Результаты отражены в таблице ниже:
Перцентили LCP | JPEG | WebP | Разница в процентах |
p50 LCP (ms) | 1628 | 1284 | -21.1% |
p75 LCP (ms) | 1752 | 1344 | -23.3% |
p95 LCP (ms) | 2140 | 1396 | -34.8% |
Увидев такие хорошие результаты, было принято решение уже на самом сайте Иви заменить формат картинок, являющихся LCP-элементом (см. примеры с сайта Иви выше): на Главной странице сайта и на карточках контента. По итогу эксперимента увидели улучшение метрики для Главной страницы на десктопной версии на 45ms, на мобильной версии — 35ms. На карточках изменений не было, но результат в целом нас устроил и открыл дорогу к дальнейшим поискам возможностей оптимизации LCP. Увы, не всегда достаточно просто внедрить новую технологию, чтобы улучшить метрики. Так что копнем глубже.
Разобравшись с теоретической частью и вооружившись инструментами мониторинга, мы в первую очередь провели анализ LCP на сайте с большим вниманием к карточкам контента в контексте мобильной версии, так как карточки контента — это большинство страниц сайта Иви, и нам очень важна их скорость работы. С результатами замеров можно подробно ознакомиться в таблице ниже:
Тестируемое окружение — прод сайта Иви, проблемный web-mobile, сетевой кэш отключен, средние результаты по 5 замерам LCP в ms
«Легенда» таблицы:
TTFB: Time To First Byte
RLD: Resource Load Delay
RLDura: Resource Load Duration
ERD: Element Render Delay
LCP Total: TTFB + RLD + RLDura + ERD
Тип страницы | Троттлинг | TTFB | RLD | RLDura | ERD | LCP Total |
Доступный к просмотру контент | Нет | 384 | 26 | 108 | 315 | 832 |
4xCPU + Slow 4G | 381 | 343 | 2286 | 2100 | 5110 | |
6xCPU + Slow 4G | 1268 | 265 | 1843 | 2153 | 5529 | |
20xCPU + Slow 4G | 3060 | 365 | 5426 | 2205 | 11055 | |
4xCPU + 3G | 453 | 1750 | 8339 | 6646 | 17188 | |
6xCPU + 3G | 945 | 1784 | 9215 | 5663 | 17606 | |
20xCPU + 3G | 3125 | 2301 | 7598 | 5120 | 18144 | |
Закрытый подпиской или покупкой контент | Нет | 380 | 16 | 179 | 279 | 854 |
4xCPU + Slow 4G | 2509 | 354 | 3128 | 707 | 6698 | |
6xCPU + Slow 4G | 4250 | 338 | 3095 | 781 | 8464 | |
20xCPU + Slow 4G | 23129 | 512 | 2896 | 1187 | 27724 | |
4xCPU + 3G | 1783 | 3023 | 11401 | 2156 | 18362 | |
6xCPU + 3G | 293 | 4220 | 10047 | 5255 | 19814 | |
20xCPU + 3G | 40548 | 1864 | 10425 | 3194 | 56030 | |
Так называемый «фейк» — карточки для SEO | Нет | 1940 | 11 | 140 | 1616 | 3706 |
4xCPU + Slow 4G | 11054 | 403 | 1770 | 9995 | 23223 | |
6xCPU + Slow 4G | 17154 | 413 | 1737 | 10283 | 29587 | |
20xCPU + Slow 4G | 68414 | 740 | 1579 | 16769 | 87502 | |
4xCPU + 3G | 16351 | 1937 | 6607 | 33641 | 58535 | |
6xCPU + 3G | 26734 | 1718 | 6605 | 34438 | 69494 | |
20xCPU + 3G | 97682 | 2141 | 6256 | 45391 | 151470 | |
Главная страница | Нет | 2171 | 40 | 103 | 84 | 2400 |
4xCPU + Slow 4G | 1373 | 82 | 2745 | 2047 | 6257 | |
6xCPU + Slow 4G | 902 | 160 | 5675 | 32 | 6768 | |
20xCPU + Slow 4G | 854 | 206 | 5176 | 233 | 6469 | |
4xCPU + 3G | 843 | 1507 | 14197 | 2283 | 18828 | |
6xCPU + 3G | 844 | 1675 | 16557 | 482 | 19557 | |
20xCPU + 3G | 997 | 1336 | 13656 | 3317 | 19304 | |
Также для облегчения анализа были сделаны дополнительные задачи (не направленные на прямое улучшение LCP). Основной задачей стало добавление графика разбивки метрики LCP в Grafana. Этот график строится на основе отправляемых данных LCP в нашу аналитическую систему. Основное отличие от графиков в CruX отчетах заключается в том, что этот график обновляется в режиме реального времени, что обеспечивает команде веба непрерывный мониторинг и анализ метрики, и в случае негативных изменений позволяет оперативно реагировать на ухудшение. Как пример — несколько раз при проблемных релизах мы очень быстро выявляли проблему и откатывали релиз, не дожидаясь пересчета метрики со стороны Google. Скрин для понимания:

Дополнительно был проведен ручной анализ DOM дерева на предмет оптимизаций LCP.
По результатам анализа были сформулированы и реализованы следующие задачи (помимо упомянутого выше эксперимента с WebP):
До начала работ по LCP на карточках контента LCP-элементом у нас являлись теги div с background-image. Гипотеза состояла в том, что если перевести LCP-элемент на тег image и обвесить его специальными атрибутами (fetchpriority = high и loading = eager), то можем получить некоторое улучшение LCP. Атрибут fetchpriority со значением high как бы говорит браузеру — этот ресурс надо загрузить как можно скорее, а атрибут loading со значением eager прямо указывает, что изображение должно загрузиться немедленно, в отличие от значения lazy. По итогам никакого улучшения не было выявлено, LCP остался в тех же значениях.
Далее решили продолжать копать тему с тегом img и решили расширить этот тег тегом picture. Тут гипотеза состояла в том, что у нас что для десктопа, что для мобильных устройств отдавалась одна и та же по размерам картинка в довольно большом разрешении. Решили добавить респонсивные постеры с помощью тега picture. Целями опять стали LCP картинки на Главной и на карточках контента. По результатам получили небольшое улучшение LCP (~35-50ms) на всем сайте.
Благодаря задаче с выводом составляющих LCP в графане заметили, что Element render Delay довольно высок, чтобы быть нормой. Решили копать в эту сторону дальше. Одной из предполагаемых причин было то, что у нас слишком загруженный Main Thread, но раскопки с использованием Perfomance в Chrome ни к чему не привели. Тогда решили зайти с другой стороны, не разбираться в кишках всего приложения и искать проблему там, а создать тестовый стенд и начать пошагово навешивать туда функционал, который в теории может замедлять Element Render Delay.
Возможно, тут возникнет вопрос — а было ли что-то по TTFB? Ответ — да, коллеги из нашей команды параллельно работали над улучшением кэширования для всего сайта. Вкратце, это ускорило TTFB и соответственно LCP по данным из аналитической системы. Впрочем, это тема для отдельной статьи, и возможно в будущем мы про это расскажем (увлекательная получится история, следите за обновлениями!).
Прицельно бьем в Element Render Delay
Вследствие неудачи ресерча ERD, решили сделать стенд — начать с простого html файлика (без экосистемы React) с картинкой (которая будет считаться как LCP-элемент) и постепенно добавлять туда разный функционал, который в теории может ухудшать или улучшать время Element Render Delay. Условия эксперимента — mobile, без учета троттлинга процессора и сети, изначально используется картинка с нашего CDN; также создан вспомогательный скрипт в head, который находит LCP-элемент и вытаскивает из него Element render delay. Далее делаем 15 замеров (перезагрузок страницы) — и скрипт выведет средний ERD. Эксперименты и результаты собраны в табличке под катом (уж очень внушительной она оказалась):
Эксперименты и результаты
Эксперимент/гипотеза | Описание гипотезы | Результат ERD по 15 замерам | Вывод |
картинка в теге img в формате JEPG без атрибутов оптимизации | посмотреть, как считается ERD, когда нет ничего в теории блокирующего ERD | 📊 Средний LCP: 284 мс ⏱️ Средний ERD: 28 мс 📈 Средний ERD%: 10,3% ✅ ОТЛИЧНО: Нормальный уровень ERD | Без блокирующих в теории фич ERD в рамках нормы |
тегу img добавлены атрибуты размеров | возможно добавление таких атрибутов ускорит отрисовку картинки браузером | 📊 Средний LCP: 568 мс ⏱️ Средний ERD: 344 мс 📈 Средний ERD%: 19,3% ✅ ОТЛИЧНО: Нормальный уровень ERD | Улучшения ERD не выявлено |
картинка с другого источника, размеры те же | предполагается, что есть проблемы с нашим CDN | В пределах нормы | По сравнению с другим источником наш CDN отдает картинку быстрее |
конвертация JPEG в WebP | проверить, как повлияет изменение формата на ERD | 📊 Средний LCP: 297 мс ⏱️ Средний ERD: 32 мс 📈 Средний ERD%: 12,0% ✅ ОТЛИЧНО: Нормальный уровень ERD | На ERD изменение формата на WebP существенно не влияет |
добавление атрибутов fetchpriority=high и loading=eager у тега img | проверить, оказывают ли эти атрибуты влияние на ERD | 📊 Средний LCP: 281 мс ⏱️ Средний ERD: 33 мс 📈 Средний ERD%: 11,9% ✅ ОТЛИЧНО: Нормальный уровень ERD | На ERD добавление атрибутов не оказывает эффекта |
добавление в head медленных шрифтов | медленные шрифты могут тормозить ERD | 📊 Средний LCP: 281 мс ⏱️ Средний ERD: 31 мс 📈 Средний ERD%: 11,6% ✅ ОТЛИЧНО: Нормальный уровень ERD | Медленные шрифты не тормозят ERD |
добавление "тяжелых" css вычислений в head | тяжелые вычисления css могут тормозить ERD | 📊 Средний LCP: 280 мс ⏱️ Средний ERD: 29 мс 📈 Средний ERD%: 10,9% ✅ ОТЛИЧНО: Нормальный уровень ERD | Также критичного ухудшения ERD не замечено |
добавление тяжелого скрипта для создания long task | тяжелые long task могут тормозить ERD | ERD ухудшился | long task ухудшают ERD примерно на время их выполнения |
добавление микротасок | Множество микротасок могут ухудшать ERD. Эксперимент запускался сначала с 60 микротасками, потом с 100, потом с 1000, потом без микротасок | В пределах нормы | Микротаски никак не влияют на ERD — на разных кол-вах микротасок изменений ERD нет вообще |
добавление счетчиков GTM, Яндекс Метрики и тп как на сайте на КК | выполнение скриптов аналитики может тормозить ERD | В пределах нормы | Счетчики аналитики никак не влияют на ERD |
добавление бандла css | проверить, оказывают ли влияние наши бандлы на ERD; Добавление в том же порядке, что и на кк (в head) | В предалх нормы | бандл css не влияет на ERD |
добавление бандла js | В пределах нормы | внезапно, но бандл js + бандлы для его работы (react ecosystem, web cypher) не влияют на ERD | |
добавление бандла плеера css | В пределах нормы | На ERD css бандл плеера не влияет | |
добавление бандла плеера js | В пределах нормы | Тут влияния бандла на ERD также нет | |
Блок бандлов через Charles | Посмотреть как влияет блокировка бандлов на ERD | Негативные изменения ERD | Если заблокирован только бандл css — сильно ухудшается ERD (на время блокировки примерно) Если заблокирован только бандл js — LCP в целом считается и отправляется по лого в шапке Если заблокированы оба бандла — LCP не считается ни в Perfomance tab, ни в расширении web-vitals хрома, не отправляется в грут после взаимодействия со страницей; отправляется кастомный LCP |
Зовем на подмогу — дополнительные эксперименты при помощи Charles
Из всех экспериментов на стенде «удался» — то есть показал явное влияние на ERD — эксперимент с блокировкой загрузки основных бандлов через Charles.
Блокировка основного js бандла
Подробнее опишу кейс, который был найден с помощью Charles. Мы обратили внимание на наши основные js и css бандлы. В них собраны скрипты и стили, которые нужны на всех разделах иви. Далее решили посмотреть, а что происходит, если загрузку этой статики «подвесить» в Charles, и увидели интересное поведение — при блокировке js бандла во вкладке Network у нас также подвисали два css файла для шапки сайта, а также для кнопки «Открыть» в приложении. Нюанс этих блоков в том, что их css лежит рядом с ними, а не в теге head. Это следствие реализации этих компонентов как Lazy-блоков. При этом эти блоки находились ДО блока, внутри которого весь основной контент страницы, включая LCP-элемент. Для понимания скрин DOM до оптимизации:
Файл со стилями шапки
Блок шапки, генерирующий css рядом с собой
Стили кнопки Открыть в приложении
Враппер, в котором лежит блок с LCP-элементом

И при этом, до тех пор, пока эти два css файла не зарезолвились, мы наблюдали пустую страницу с фоном. Исходя из этого родилась задача — просто перенести эти блоки ниже блока с LCP-элементом, а стилями визуально сделать так, как будто переноса не было. Но к сожалению оказалось, что этот вариант оптимизации в отношении шапки сайта нам не подходит, так как в теории перенос шапки сильно сломает SEO. Пришлось откатить правки и подумать над другим решением. Обратили внимание, что именно Lazy рельсы компонента создают его css файл рядом. Поэтому решили сделать шапку обычным компонентом — стили шапки стали собираться в общем css бандле. Блок кнопки Открыть в приложении оставили после враппера. По итогу это почти простое решение дало очень мощный выхлоп — значительное улучшение метрики LCP на всем сайте в целом и на основных разделах в частности: ~200-250ms для Mobile, ~150-200ms для Desktop. Это подтвердилось как на наших внутренних графиках, так и на CrUX отчетах.
Блокировка основного css бандла
Воодушевленные таким успехом, мы решили повторить эксперимент с подвисанием, только в этот раз с бандлом стилей. В этом кейсе все остальные скрипты и стили продолжали загружаться, но тем не менее, пока css бандл был в состоянии pending, на странице не было видно LCP-элемента. При снятии блокировки в charles LCP-элемент появлялся, а сама метрика, а конкретно ее составляющая Element Render Delay считалась примерно в ТО ЖЕ время, на которое была заблокирована загрузка css бандла. По результатам этого эксперимента родилась задача — сделать так, чтобы css бандл не блокировал рендер DOM дерева, а также добавить critical.css (или skeleton.css), который был бы легковесным и его скачивание занимало гораздо меньше времени, чем скачивание основного бандла. В рамках эксперимента сделали это только для карточек контента и только на мобильной версии сайта, под аб-тестом. По итогу зафиксировали значительное улучшение метрики LCP на mobile (~100-110ms), а конкретно составляющий LCP — Element Render Delay. Другие составляющие LCP без изменений (что, собственно, и ожидалось).
Из желтой зоны в зеленую — итоги наших оптимизаций
До начала экспериментов по данным CrUX LCP для мобильных устройств подбирался к желтой зоне и даже в определенные временные промежутки попадал в нее, в пике значение было 2521ms. Но в итоге нашими экспериментами удалось снизить это значение на 419ms, до 2102ms по последним данным CrUX, в пересчете на проценты ~17%. Считаем это хорошим результатом как по абсолютным цифрам, так и по относительным. При этом стоит отметить, что мы пришли к выводу, что именно со стороны клиента возможности оптимизации мы исчерпали.
Приведу рекомендации тем разработчикам, которые либо планируют, либо уже занимаются оптимизацией LCP:
CrUX и его показатели — ваш основной ориентир
Очень удобно настроить на своей стороне инструменты мониторинга — обязательно сделайте это!
Нащупайте больные места вашей LCP, используя анализ подметрик — это покажет, в каких местах у вас проблемы. Для нас это стали показатели Element Render Delay и TTFB
Следите за LCP-картинками — мир веб-разработки развивается стремительно, даруя новые возможности для оптимизации их загрузки
Проанализируйте поведение ваших бандлов/скриптов при различных кейсах — велика вероятность их прямого влияния на LCP
На этом мой рассказ подходит к концу. Надеюсь, он был полезен для вас. Желаю вам удачи в ваших экспериментах!
