Довольно многие, кто близок к миру 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) это:

  1. LCP (Largest Contentful Paint) — «Как быстро загружается основное содержимое?» (Метрика загрузки)

  2. INP (Interaction to Next Paint) — «Как быстро сайт реагирует на клики, тапы, нажатия клавиш?» (Метрика отзывчивости). (Примечание: заменил FID в 2024 году)

  3. 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. Эти отчеты находятся в открытом доступе и можно смотреть состояние метрик в принципе для любого сайта. Вот ссылка-пример такого отчета для сайта Иви:

https://cruxvis.withgoogle.com/#/?view=loadingperf&url=https%3A%2F%2Fwww.ivi.ru%2F&identifier=origin&device=PHONE&periodStart=0&periodEnd=-1&display=p75s

В качестве упражнения, попробуйте посмотреть CrUX отчеты ваших любимых сервисов.

Главная панель метрики LCP
Главная панель метрики LCP

Тут можно обратить внимание на вкладку 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-элементом:

  1. TTFB — Time to first byte — время от начала навигации до получения первого байта HTML-документа от сервера. Эта метрика показывает скорость работы бэкенда и сети. Важно отметить, что эта метрика также считается отдельной самостоятельной метрикой web-vitals, но при этом входит в конечный LCP

  2. Resource Load Delay — задержка начала загрузки LCP-элемента. Это время между TTFB и моментом, когда браузер фактически начал скачивание LCP-элемента. Большая задержка означает, что более важный ресурс ждал, пока скачаются менее важные

  3. Resource Load Duration — собственно время скачивания LCP-элемента. Тут все просто. На значение этой метрики влияет размер изображения, его степень сжатия, скорость работы сети и наличие кэша

  4. 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

«Легенда» таблицы:

  1. TTFB: Time To First Byte

  2. RLD: Resource Load Delay

  3. RLDura: Resource Load Duration

  4. ERD: Element Render Delay

  5. 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 до оптимизации:

  1. Файл со стилями шапки

  2. Блок шапки, генерирующий css рядом с собой

  3. Стили кнопки Открыть в приложении

  4. Враппер, в котором лежит блок с 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

На этом мой рассказ подходит к концу. Надеюсь, он был полезен для вас. Желаю вам удачи в ваших экспериментах!