Урок по треку Браузер и DOM 7 мин

Производительность и Core Web Vitals

LCP, INP и CLS: что измеряют, пороги и как их улучшать. Ленивая загрузка и приоритеты.

Быстрый сайт это не «маленький бандл», а три вещи, которые чувствует пользователь: как быстро появился главный контент, как быстро страница откликается на действия и не прыгает ли вёрстка. 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.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.