Инженерная практика

Core Web Vitals для React-сайта: измерить, объяснить, улучшить

Как найти причину медленной загрузки, задержки клика и скачков страницы. Разделяем Lighthouse и полевые данные, составляем план измерений и проверок.

Страница быстро открылась на вашем ноутбуке, но на телефоне посетитель ждёт большой заголовок, кнопка откликается с задержкой, а форма уезжает после загрузки картинки. Одного числа «скорость сайта» недостаточно, чтобы понять эти три проблемы. Core Web Vitals дают общий язык для загрузки, реакции на действие и устойчивости компоновки.

Три метрики, три разных вопроса

  • LCP: когда появился самый крупный видимый элемент содержимого? Хороший ориентир - не более 2,5 секунды.
  • INP: как быстро страница отвечает на пользовательские взаимодействия? Хороший ориентир - не более 200 мс.
  • CLS: насколько неожиданно сдвигается компоновка? Хороший ориентир - не более 0,1.

Для оценки большинства пользователей эти границы рассматривают на 75-м перцентиле, отдельно по типу устройства. Среднее значение может скрыть большую группу медленных посещений. Хорошая медиана одного компьютера не доказывает хороший результат всей аудитории. Поэтому в отчёте указывайте источник данных, период и устройство, а не только зелёный индикатор.

Разделите лабораторию и реальные посещения

Lighthouse помогает воспроизвести загрузку в заданных условиях и найти узкое место до публикации. Полевые данные отражают реальную сеть, устройства, контент и действия посетителей. Если сайт недавно обновился или у него мало трафика, данных по конкретному URL может не быть. Не заменяйте отсутствие полевых данных утверждением «всё прошло». Зафиксируйте, какие измерения доступны.

TBT показывает время блокировки в лабораторной загрузке, но не равен INP. Для взаимодействия откройте страницу, выполните реальные действия и запишите профиль: поиск, раскрытие меню, ввод в форму, переключение фильтра. Даже спокойная загрузка не исключает тяжёлый обработчик после первого клика. Техническая проверка должна соответствовать пользовательскому сценарию.

LCP: найдите элемент и разложите ожидание

Определите, какой элемент стал LCP: текст, иллюстрация, постер или другой блок. Затем разделите время на ожидание HTML, обнаружение ресурса, его загрузку и возможность отрисовки. Если сервер долго готовит HTML, сжатие изображения не устранит всю задержку. Если картинка объявляется только после выполнения JavaScript, размер файла - не единственная причина.

JavaScript// Изображение первого экрана: размеры и приоритет явны <img src="/hero-640.webp" srcSet="/hero-640.webp 640w, /hero-1280.webp 1280w" sizes="(min-width: 1024px) 480px, 90vw" width="1280" height="853" alt="Схема работы с данными в приложении" fetchPriority="high" />

Не назначайте высокий приоритет всем изображениям: это снова создаст конкуренцию. Ресурс первого экрана не стоит лениво загружать, если он важен для LCP. Указанные width и height задают соотношение сторон и помогают зарезервировать место; адаптивный CSS должен сохранять эту пропорцию. В Next.js используйте соответствующий механизм Image и проверяйте итоговый HTML, а не только props в исходнике.

INP: обработчик - только часть ответа

Задержка взаимодействия включает ожидание начала обработки, выполнение обработчика и ожидание следующего визуального результата. Не ищите проблему только внутри onClick. Основной поток может быть занят другой задачей ещё до клика. После обработчика большая перестройка DOM или дорогой layout тоже задержит видимый ответ. Найдите длинную работу в профиле и проверьте, связана ли она с вашим действием.

Для большого списка рассмотрите уменьшение числа одновременно отрисованных элементов и более дешёвую модель поиска. Для независимого CPU-расчёта можно оценить Worker. Не добавляйте useMemo во все компоненты в надежде «ускорить React»: сначала найдите конкретную повторяющуюся дорогую операцию. Микрозадача не является отдельным потоком - подробнее в разборе event loop.

CLS: резервируйте место для реального содержимого

Проверьте размеры картинок, блоки с асинхронными данными, подмену шрифта и сообщения формы. Skeleton может помочь, если его геометрия похожа на итоговый блок. Универсальная пустая полоса высотой 20 px не спасёт карточку, которая после ответа вырастет до 300 px. Сохранение места должно учитывать содержание, а не служить декорацией.

Протокол измерения, который можно повторить

  1. Выберите URL и версию сайта. Зафиксируйте устройство, эмуляцию сети, CPU, наличие кеша и состояние авторизации.
  2. Сделайте несколько одинаковых лабораторных запусков. Сохраните сырые отчёты, укажите медиану и разброс, а не только лучший результат.
  3. Найдите LCP-элемент и самый тяжёлый пользовательский сценарий. Запишите наблюдаемую причину и предположение отдельно.
  4. Измените одну связанную вещь: доставку ресурса, объём вычислений или резервирование места.
  5. Повторите тот же протокол и проверьте функциональные сценарии, доступность и содержание страницы.
  6. После публикации сопоставьте лабораторный результат с доступными полевыми данными новой версии.

Ускорять сайт удалением нужного пользователю текста - плохой обмен. Сначала улучшите доставку, структуру и работу с ресурсами. Для менторства по frontend полезно приносить на ревью не только итоговые баллы, но и короткое объяснение причины, изменения и оставшихся ограничений. Начать можно с критериев учебного проекта.

Первичные источники

Определения и отличие лаборатории от поля: web.dev - Web Vitals. Диагностика загрузки: Optimize LCP. Диагностика взаимодействия: Optimize INP. Метрики статьи описывают критерии измерения, а не результаты этого или любого другого сайта.

Вопросы по теме

Что означает зелёный Lighthouse Performance?
Это хороший лабораторный результат конкретного запуска. Он не доказывает прохождение LCP, INP и CLS у реальных пользователей на 75-м перцентиле.
Можно ли измерить INP обычной загрузкой Lighthouse?
Обычный навигационный аудит не воспроизводит пользовательские взаимодействия для INP. TBT полезен как лабораторный индикатор, но это другая метрика.
Почему после нового выката полевые данные ещё старые?
Полевые отчёты агрегируют реальные посещения за период. Свежий лабораторный результат можно получить сразу, но он не заменяет накопление данных новой версии.

Читайте также

Все статьи

Обсудим вашу подготовку?

Напишите, что уже умеете и с чем возникли трудности. Если есть проект, пришлите ссылку на него.

Отвечаю лично, поэтому прошу рассказать о ситуации подробно. Все поля обязательны, кроме отмеченных. После отправки покажу ссылку на мой Telegram: напишите туда, и начнём разговор.

Что не получается, что уже пробовали. От 100 знаков, сейчас 0.
Где работали или учились, сколько лет, какой стек, сколько откликов и собеседований. От 100 знаков, сейчас 0.
PDF или DOCX, до 5 МБ. Файл видит только администратор.
GitHub, hh, LinkedIn, сайт. Можно несколько, через пробел или с новой строки.