Быстрый сайт это не «маленький бандл», а три вещи, которые чувствует пользователь: как быстро появился главный контент, как быстро страница откликается на действия и не прыгает ли вёрстка. Google формализовал их в Core Web Vitals.
Три метрики
| Метрика | Что измеряет | Хорошо | Плохо |
|---|---|---|---|
| LCP (Largest Contentful Paint) | когда отрисован самый крупный элемент в первом экране | до 2,5 с | больше 4 с |
| INP (Interaction to Next Paint) | задержка от действия пользователя до следующей отрисовки | до 200 мс | больше 500 мс |
| CLS (Cumulative Layout Shift) | насколько неожиданно сдвигается вёрстка | до 0,1 | больше 0,25 |
Оценивают по 75-му перцентилю реальных визитов: метрика «хорошая», если 75% визитов укладываются в порог.
INP заменил FID в марте 2024 года. FID мерил только задержку первого взаимодействия и только до начала обработки. INP смотрит на все клики, тапы и нажатия клавиш за визит и берёт почти худшее, причём учитывает всё время до появления кадра: ожидание, сам обработчик и отрисовку.
Как улучшать LCP
LCP-элемент обычно это главная картинка, баннер или крупный заголовок. Время складывается из: ответа сервера (TTFB), задержки начала загрузки ресурса, самой загрузки и отрисовки.
- Ускорить сервер и кешировать HTML (CDN).
- Не лениво грузить LCP-картинку:
loading="lazy"на ней только вредит. - Дать ей высокий приоритет:
<img fetchpriority="high">или<link rel="preload" as="image">. - Убрать блокирующий рендер CSS и синхронные скрипты в
<head>(defer,async). - Сжать картинки, отдавать AVIF или WebP и нужный размер через
srcset. - Не рисовать главный контент только на клиенте после загрузки JS: SSR или статическая генерация.
Как улучшать INP
INP плохой, когда главный поток занят. Любая длинная задача (дольше 50 мс) задерживает обработку клика.
- Дробить тяжёлую работу и отдавать управление браузеру:
await scheduler.yield()(Chrome; в остальных запасной вариант черезsetTimeout). - Сначала показать отклик (спиннер, нажатая кнопка), потом делать тяжёлое.
- Выносить вычисления в Web Worker.
- Уменьшать JS: код-сплиттинг, удалять лишние библиотеки.
- Избегать layout thrashing в обработчиках.
- В React:
startTransitionдля неважных обновлений, виртуализация длинных списков.
async function handleClick() {
showSpinner();
await new Promise((r) => setTimeout(r, 0)); // дать браузеру отрисовать спиннер
heavyWork();
}
Как улучшать CLS
Сдвиг возникает, когда элемент появляется или меняет размер и толкает соседей.
- Указывать
widthиheightу картинок и видео (илиaspect-ratio), чтобы место резервировалось заранее. - Резервировать место под рекламу, баннеры, встраиваемые блоки.
- Не вставлять контент над уже видимым, кроме ответа на действие пользователя (сдвиги в течение 500 мс после ввода не считаются).
- Шрифты:
font-display: optionalили подбор запасного шрифта черезsize-adjust, чтобы подмена не меняла размеры строк. - Анимировать
transform, а неtopилиheight: трансформации не вызывают сдвиг раскладки.
Где мерить
- Лабораторные данные: Lighthouse, вкладка Performance в DevTools. Удобно искать причины, но это одна машина и одна сеть. INP в лаборатории не измеряется, вместо него Total Blocking Time.
- Полевые данные (RUM): CrUX (статистика Chrome по реальным пользователям), библиотека
web-vitalsдля своей аналитики. Именно они идут в оценку.
Загрузка ресурсов
defer: скрипт качается параллельно, выполняется после разбора HTML, по порядку.async: выполняется сразу как скачался, порядок не гарантирован.preloadдля критичного ресурса текущей страницы,preconnectдля раннего соединения с чужим доменом,prefetchдля ресурса следующей навигации.loading="lazy"для картинок и iframe ниже первого экрана.- Сжатие Brotli, кеширование статики с хешем в имени на год.
Частые ошибки
- Ставить
loading="lazy"на главную картинку первого экрана. - Говорить про FID как актуальную метрику.
- Оптимизировать только по Lighthouse, не глядя на полевые данные.
- Думать, что CLS это про скорость загрузки. Это про стабильность.
Что спросят на собесе
- Что такое Core Web Vitals, какие пороги и почему FID заменили на INP.
- Как найти и ускорить LCP-элемент.
- Откуда берётся плохой INP и как его лечить.
- Что вызывает CLS и как его избежать.
- Чем
asyncотличается отdefer, аpreloadотprefetch.