Core Web Vitals: полный обзор

Что измеряют LCP, INP и CLS, пороги, двенадцать причин плохих метрик с решениями, полевые и лабораторные данные, четыре примера с цифрами до и после, ошибки и правила.

Стек и технологии Обновлено

Коротко

Core Web Vitals — три метрики Google, которые описывают, какой страница кажется живому посетителю: LCP — как быстро появляется главное содержимое, INP — как быстро страница отвечает на клики и касания, CLS — насколько прыгает раскладка. Страница проходит, когда 75% настоящих визитов укладываются в пороги: LCP до 2,5 секунды, INP до 200 миллисекунд, CLS до 0,1. Google учитывает их в поиске как часть удобства страницы, но главная ценность в другом: быстрая и устойчивая страница удерживает людей и больше продаёт. Большинство проблем идёт от нескольких причин — тяжёлые картинки, шрифты, скрипты и медленный сервер.

Core Web Vitals коротко

Главные факты одной таблицей: что измеряется, как оценивается страница и откуда берутся данные.

Что это
Метрики Google для реального опыта посетителя: загрузка, отклик, устойчивость
Метрики
LCP, INP, CLS; INP заменил FID в марте 2024 года
Как оценивается
75-й процентиль настоящих визитов за 28 дней, отдельно для телефонов и компьютеров
Источник данных
Отчёт Chrome User Experience Report (CrUX) — обезличенные данные пользователей Chrome
Где смотреть
PageSpeed Insights, Search Console, Chrome DevTools
В поиске
Часть сигналов удобства страницы с 2021 года; соответствие содержимого запросу по-прежнему важнее
Свой замер
Библиотека web-vitals от Google — те же цифры от ваших собственных посетителей

Метрики и их пороги

Три Core Web Vitals и две вспомогательные метрики, которые их объясняют. Пороги взяты из библиотеки web-vitals от Google.

МетрикаЧто измеряетХорошоТребует работыПлохо
LCP когда появляется самый крупный элемент первого экрана до 2,5 с 2,5–4 с больше 4 с
INP сколько клик или касание ждёт видимого ответа до 200 мс 200–500 мс больше 500 мс
CLS насколько раскладка сдвигается сама до 0,1 0,1–0,25 больше 0,25
FCP когда появляется хоть что-то — вспомогательная до 1,8 с 1,8–3 с больше 3 с
TTFB когда сервер начинает отвечать — вспомогательная до 0,8 с 0,8–1,8 с больше 1,8 с

Что портит метрики и как это исправить

Двенадцать частых причин — с метрикой, которую они бьют, и решением.

ПричинаМетрикаРешение
Тяжёлая картинка на первом экране LCP AVIF или WebP, srcset, fetchpriority="high"
Картинка первого экрана грузится лениво LCP убрать у неё loading="lazy"
Медленный ответ сервера LCP кэш, меньше запросов к базе, CDN
Шрифты со стороннего сервиса LCP свои файлы woff2 с подрезкой
Содержимое рисует JavaScript LCP отдавать HTML с сервера
Долгие задачи в обработчиках кликов INP сначала отрисовать реакцию, потом работать
Тяжёлые сторонние скрипты INP загружать позже или убрать
Огромный DOM INP меньше элементов, content-visibility
Картинки без размеров CLS width и height в HTML
Поздно загружаемые баннеры и виджеты CLS зарезервированное место через min-height
Веб-шрифт заменяет запасной CLS подогнанный запасной шрифт или font-display: optional
Анимации top и height CLS анимировать transform и opacity

Полевые и лабораторные данные

  1. Полевые данные

    Настоящие визиты из CrUX — именно их Google использует в поиске и показывает в Search Console.

  2. Лабораторные данные

    Один прогон Lighthouse на эмулированном телефоне — хорош для поиска причин, но не для итоговой оценки.

  3. Почему они расходятся

    У настоящих посетителей разные телефоны, сети и страницы; в лаборатории — одно устройство и одна загрузка.

  4. INP в лаборатории

    Lighthouse не кликает, поэтому показывает Total Blocking Time — подсказку, а не сам INP.

  5. 28 дней задержки

    Полевые данные собираются за 28 дней — исправление полностью видно в отчётах примерно через месяц.

  6. Небольшие сайты

    При малом трафике в CrUX нет данных — тогда помогает собственный замер через web-vitals.

Замер и исправления: 4 примера

Собственный замер и по одному исправлению на каждую метрику. Каждый пример проверен в браузере на тестовом стенде, с цифрами до и после.

Свои полевые данные

После клика и закрытия вкладки сервер получил все три метрики с оценками.

vitals.js
// Метрики настоящих посетителей: измеряются в их браузерах, собираются на нашем сервере
import { onCLS, onINP, onLCP } from 'web-vitals';

function send(metric) {
  const body = JSON.stringify({
    name: metric.name,     // LCP, INP или CLS
    value: metric.value,   // миллисекунды; у CLS — оценка без единиц
    rating: metric.rating, // good, needs-improvement или poor
    page: location.pathname,
  });
  // sendBeacon переживает закрытие вкладки — именно тогда INP и CLS становятся окончательными
  if (!navigator.sendBeacon('/api/vitals', body)) {
    fetch('/api/vitals', { method: 'POST', body, keepalive: true });
  }
}

onLCP(send);
onINP(send);
onCLS(send);

LCP: картинка первого экрана

Главная картинка запрашивается с приоритетом High и становится элементом LCP; нижняя запрашивается только после прокрутки.

index.html
<!-- Картинка первого экрана: браузер грузит её первой и никогда не лениво -->
<img src="/img/hero-1200.avif"
     srcset="/img/hero-800.avif 800w, /img/hero-1200.avif 1200w"
     sizes="(max-width: 800px) 100vw, 1200px"
     width="1200" height="630" alt="Дубовый стол на светлой кухне"
     fetchpriority="high">

<!-- Картинки ниже: грузятся, только когда человек до них докрутит -->
<img src="/img/table-top.webp" width="600" height="400"
     alt="Столешница из дуба крупным планом" loading="lazy" decoding="async">

CLS: зарезервированное место

Одна и та же страница с поздней картинкой, плеером и промоблоком: CLS 0,326 без этих правил и 0 с ними.

stable.css
/* Место резервируется до того, как придёт содержимое, — ничего ниже не прыгает */
img,
video {
  max-width: 100%;
  height: auto;          /* пропорции берутся из width и height в HTML */
}

.embed {
  aspect-ratio: 16 / 9;  /* видеоплееры, карты и другие iframe */
}
.embed > iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

.promo-slot {
  min-height: 250px;     /* блок, который скрипт заполнит позже */
}

INP: ответ до работы

Обработчик с работой на 300 мс: без этого приёма клик ждал ответа 304 мс, с ним — 16 мс.

filter.js
// Дать браузеру отрисовать реакцию до тяжёлой работы —
// клик сразу получает видимый ответ, а именно его и измеряет INP
const afterPaint = () =>
  new Promise((resolve) => requestAnimationFrame(() => setTimeout(resolve, 0)));

button.addEventListener('click', async () => {
  button.classList.add('is-loading'); // отрисуется сразу
  await afterPaint();
  const items = filterCatalogue();    // тяжёлая часть — уже после отрисовки
  render(items);
  button.classList.remove('is-loading');
});

Частые ошибки с Core Web Vitals

  1. Гнаться за 100 в Lighthouse

    Поиск берёт полевые данные; идеальная лабораторная оценка при плохих полевых ничего не меняет.

  2. Проверять на быстром компьютере

    Большинство визитов — со средних телефонов в мобильной сети.

  3. Ленивая загрузка всего подряд

    loading="lazy" на картинке первого экрана откладывает LCP.

  4. Проверять только главную

    Карточки товаров и статьи приносят большую часть трафика и обычно страдают сильнее.

  5. Скрипты всех сервисов подряд

    Чаты, пиксели и виджеты складываются и портят INP сильнее собственного кода.

  6. Ждать результата назавтра

    Полевые данные догоняют за 28 дней — собственный замер показывает эффект сразу.

7 правил хороших Core Web Vitals

  1. 01

    Бюджет до дизайна

    Целевые цифры согласуются до первого макета — тогда дизайн с ними не спорит.

  2. 02

    HTML с сервера

    Главное содержимое приходит в первом ответе, а не после скриптов.

  3. 03

    Одна приоритетная картинка

    fetchpriority="high" — только на картинке первого экрана, loading="lazy" — на остальных.

  4. 04

    Свои шрифты

    woff2 только с нужными символами, со своего сервера.

  5. 05

    Размеры для всего, что грузится

    Картинки, видео, iframe и виджеты получают место до того, как придут.

  6. 06

    Сторонние скрипты по списку

    Каждый обоснован и грузится после главного содержимого.

  7. 07

    Свой замер в рабочем проекте

    web-vitals присылает цифры настоящих посетителей — проблемы видны раньше отчётов.

Вопросы о Core Web Vitals

Что такое Core Web Vitals?

Три метрики Google для реального опыта посетителя: LCP — загрузка, INP — отклик, CLS — устойчивость.

Влияют ли они на позиции в поиске?

Да, как часть удобства страницы, но соответствие содержимого запросу важнее; из равных страниц выигрывает более быстрая.

Что стало с FID?

В марте 2024 года его заменил INP: FID измерял только первый клик, INP — все.

Почему PageSpeed Insights каждый раз разный?

Лабораторная часть — один прогон с шумом сети и сервера; полевая часть вверху отчёта стабильна.

Где увидеть данные своего сайта?

В Search Console, в отчёте Core Web Vitals, и в PageSpeed Insights для конкретной страницы.

У сайта нет полевых данных. Почему?

CrUX показывает только сайты и страницы с достаточным числом визитов; пробел закрывает собственный замер через web-vitals.

Мешают ли CMS и конструкторы?

Часто да: темы, модули и блоки — от WordPress до 1С-Битрикс и Tilda — приносят скрипты и стили на каждую страницу, нужны они там или нет.

Форма

Ускорить
сайт

Вывожу Core Web Vitals в зелёную зону на реальных телефонах: картинки, шрифты, скрипты и сервер. На новых проектах бюджет метрик согласую до начала дизайна. Расскажите о сайте — отвечу в течение рабочего дня.

Или пишите на [email protected]