Скорость сайта

INP вместо FID: что изменилось и как правильно замерить

Interaction to Next Paint заменил FID в Core Web Vitals. Как замерить INP в PageSpeed и Метрике и что делать, если значение красное.

обновлено 10 минут чтения 1 Дмитрий Акиндинов
Содержание
  1. Чем INP отличается от FID
  2. Почему INP стал хуже у тех же сайтов
  3. Где смотреть честные значения
  4. Как замерить самому через Web Vitals API
  5. Главные источники плохого INP и как с ними бороться
  6. Особые случаи на популярных движках
  7. Реалистичная цель и реалистичные сроки
  8. Частые вопросы

В марте 2024 года INP заменил FID в составе Core Web Vitals. Разница принципиальная: FID мерил задержку только первого действия, INP смотрит на всё, что человек нажал за визит, и берёт худший случай. Поэтому у тех же сайтов зелёная метрика стала жёлтой.

В марте 2024 года Google официально заменил First Input Delay на Interaction to Next Paint в составе Core Web Vitals. Прошло два года, многие владельцы сайтов до сих пор не пересмотрели свои дашборды и удивляются, почему PageSpeed Insights показывает жёлтое или красное там, где раньше было зелёное. Метрика реально стала строже, и сайты, которые на FID были ниже 100 миллисекунд, на INP легко выезжают за 300, потому что измеряется уже совсем другое.

Разберу, что именно изменилось, на каких сайтах прилетает в первую очередь и какие конкретные шаги дают предсказуемое улучшение INP.

Курсор кликает по кнопке, рядом секундомер измеряет отклик

Чем INP отличается от FID

FID измерял задержку обработки только одного, самого первого взаимодействия пользователя со страницей. Кликнули кнопку, и засекалось, сколько браузер думал, прежде чем начать обрабатывать клик. Если первая кнопка отвечала быстро, FID был зелёным, и неважно, что через 5 секунд при следующем клике страница висла на 800 миллисекунд.

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

Условные пороги INP по Web Vitals: — меньше 200 миллисекунд: зелёная зона. — от 200 до 500: жёлтая. — больше 500: красная.

FID был куда мягче: 100 и 300 миллисекунд. Поэтому сайты, которые когда-то проходили FID без правок, на INP часто падают.

Считается на странице 75-й процентиль реальных пользователей. То есть в Core Web Vitals идёт значение, ниже которого находится 75 процентов всех взаимодействий за 28 дней. Среднее или медиана не используются, потому что они скрывают редкие, но болезненные тормоза.

Почему INP стал хуже у тех же сайтов

Главная причина: INP измеряет не только клик по первой кнопке, но клик по любой кнопке через 30 секунд после загрузки, когда у вас давно отрендерился весь JavaScript, и тяжёлые скрипты висят на главном потоке.

Что обычно даёт сильный рост INP:

  • Тяжёлые внешние скрипты: чаты типа JivoSite, Carrot Quest, виджеты ритейл-аналитики, пиксели Facebook и VK, всё это спускает в главный поток лишнюю работу.
  • Замусоренный jQuery с десятками плагинов на типичной WordPress-теме старше 5 лет.
  • Большие SPA-приложения с тяжёлой иерархией компонентов, где клик по кнопке тянет за собой реактивный пересчёт половины DOM.
  • Битрикс с большим количеством компонентов на странице каталога, обрабатывающих фильтры на стороне клиента.
  • Slider Revolution, Visual Composer, WPBakery и другие комбайны вёрстки, которые подключают много JS.

FID этого не видел, потому что измерял только первую секунду активности. INP видит каждый клик за всю сессию.

Где смотреть честные значения

PageSpeed Insights, секция Core Web Vitals Assessment. INP идёт сразу под LCP. Это field-данные из Chrome User Experience Report, поэтому они показываются только если ваш сайт собрал достаточно реальных визитов в Chrome.

Search Console, отчёт Опыт > Core Web Vitals. Если у вас сайт российский и Search Console не открывается, придётся смотреть только через PageSpeed.

Яндекс Метрика, раздел Технологии > Время загрузки. С 2024 года Метрика показывает INP вместе с другими Web Vitals в реальных условиях ваших пользователей.

Chrome Web Vitals Extension. Маленькое расширение для самого Chrome, показывает текущие метрики в углу страницы. Незаменимо при ручной проверке.

Лабораторно через Lighthouse в DevTools. Открываете Performance или Lighthouse, прогоняете аудит, получаете оценку. Лабораторное значение даёт примерное представление, но не равно полевому.

Важная оговорка: PageSpeed Insights в lab-режиме часто не показывает INP вообще, потому что он измеряется по реальным взаимодействиям, а лаборатория их не имитирует. Вы увидите только field INP. Поэтому если у сайта мало посетителей, поле может быть пустое, и тогда лучше прогонять собственные измерения через Web Vitals JS API.

Как замерить самому через Web Vitals API

Если хочется честных цифр для своего сайта, без ожидания, пока CrUX наберёт данных, есть открытая библиотека web-vitals от Google. Подключается одной строкой и пишет метрики либо в Метрику, либо в свой бэкенд.

Минимальный сниппет:

<script type="module">
import { onINP, onLCP, onCLS } from 'https://unpkg.com/web-vitals@4?module';

function send(metric) {
  // Отправляем в Метрику как пользовательский параметр
  if (window.ym) {
    ym(00000000, 'params', {
      [metric.name]: Math.round(metric.value),
      [`${metric.name}_rating`]: metric.rating,
    });
  }
  // Дублируем в консоль для дебага
  console.log(metric.name, metric.value, metric.rating);
}

onINP(send);
onLCP(send);
onCLS(send);
</script>

Замените 00000000 на свой ID счётчика Метрики. Через несколько часов в Метрике в Параметрах визитов появятся значения INP, LCP, CLS, разбитые по сегментам.

Так вы получаете живой дашборд INP по реальным пользователям, без зависимости от CrUX и без задержек.

Главные источники плохого INP и как с ними бороться

В порядке частоты в моих аудитах.

1. Длинные задачи в главном потоке

Главный поток браузера один. Если на нём висит JS-задача длительностью 300 миллисекунд, она блокирует и обработку клика, и отрисовку.

Как искать: DevTools > Performance > запись прогона, ищем красные Long Tasks дольше 50 мс. Или DevTools > Performance Insights, там список тяжёлых задач с указанием функции.

Лечение разное:

Разбить большую задачу на мелкие через setTimeout(..., 0) или современный scheduler.postTask. Это не ускоряет работу, но даёт браузеру окна для обработки клика между кусками.

async function processManyItems(items) {
  for (let i = 0; i < items.length; i++) {
    if (i % 50 === 0) {
      // отдаём управление браузеру
      await new Promise(r => setTimeout(r, 0));
    }
    handleOne(items[i]);
  }
}

Перенести тяжёлую работу в Web Worker, если она не требует доступа к DOM. Парсинг JSON, агрегация чисел, сжатие, валидация форм с большими словарями.

Удалить лишний код. Если у вас на странице 700 КБ JavaScript, и используется реально 100 КБ, остальное чистое замедление. Tree-shaking, code-splitting, отключение неиспользуемых плагинов.

2. Тяжёлые сторонние скрипты

Чаты, аналитика, рекламные SDK, виджеты обратного звонка. Каждый раз при клике могут срабатывать обработчики этих скриптов и блокировать главный поток.

Лечение:

Подключайте сторонние скрипты с async или defer. Так они не блокируют рендер.

Используйте Partytown или подобные обёртки, которые перенаправляют сторонние скрипты в Web Worker. На WordPress есть плагин Partytown, на Astro и Next.js свои интеграции.

Загружайте сторонние скрипты лениво. Чат не нужен в первые 3 секунды, можно подгрузить через IntersectionObserver или после первого взаимодействия пользователя.

const loadChat = () => {
  const s = document.createElement('script');
  s.src = 'https://widget.example/chat.js';
  s.async = true;
  document.head.append(s);
};
addEventListener('mousemove', loadChat, { once: true });
addEventListener('scroll', loadChat, { once: true });
addEventListener('touchstart', loadChat, { once: true });

Откажитесь от мёртвых скриптов. Я регулярно вижу на сайтах подключения старого Google Tag Manager, Hotjar, Pixel, которые никто не настраивал годами и которые ничего не делают, кроме замедления.

3. Слишком много обработчиков событий

Привязали click к каждому из 300 элементов на странице. При первом нажатии браузер прогоняет коллбеки, и если они длинные, INP плохой.

Лечение: делегирование событий. Один обработчик на родителе, внутри проверяете, по какому ребёнку кликнули.

document.querySelector('.products').addEventListener('click', (e) => {
  const btn = e.target.closest('button.buy');
  if (!btn) return;
  handleBuy(btn.dataset.id);
});

Такой код срабатывает быстрее, а сама привязка не делает 300 операций при загрузке.

Спидометр с зелёно-жёлто-красными зонами

4. Тяжёлый рендер на каждое взаимодействие

В React или Vue клик по чекбоксу вызывает перерисовку всего списка, а не только одного элемента. Виртуальный DOM делает свою работу, но если списков несколько по 500 элементов, итого может уходить 200-400 миллисекунд.

Лечение классическое для SPA:

Мемоизация компонентов через React.memo, useMemo, useCallback. Перерисовываются только то, что реально изменилось.

Виртуализация длинных списков через react-window, react-virtual, vue-virtual-scroller. На экране отрисовываются только видимые карточки.

Раздельные стейты. Если у вас один большой useState на всю страницу, любое изменение перерисовывает всё. Разбивайте на локальные компоненты со своими стейтами.

В классическом сайте на WordPress без SPA проблема обычно меньше, но приходит другой подвид: jQuery-плагины, которые при клике по чекбоксу пересчитывают всю фильтрацию через всю страницу.

5. Анимации и переходы, блокирующие отрисовку

Не все анимации одинаковы. CSS-анимации через transform и opacity идут на GPU и почти не нагружают главный поток. Анимации через top, left, width, height дают layout и paint на каждый кадр, главный поток просыпается.

Лечение: переписать анимации на transform: translate(...) и opacity. Это базовая практика, но я регулярно вижу таблицы и слайдеры, которые до сих пор анимированы через left.

/* плохо */
.menu { left: -300px; transition: left 0.3s; }
.menu.open { left: 0; }

/* хорошо */
.menu { transform: translateX(-100%); transition: transform 0.3s; }
.menu.open { transform: translateX(0); }

6. requestAnimationFrame и setInterval-полтергейсты

Иногда на сайте крутится скрипт, который раз в секунду перерисовывает что-нибудь незаметное. Тикер новостей, эффект параллакса, загрузчик в углу. Каждый тик блокирует главный поток на 5-20 миллисекунд, и если попасть в момент клика, INP в этой точке прыгает.

Найти такие скрипты можно через DevTools > Performance > запись 5 секунд без активности. Если в записи постоянные ровные блоки JS, у вас фоновая задача жуёт CPU.

Лечение: либо удалить, если эффект не критичен, либо перевести в Web Worker, либо запускать только когда вкладка активна (document.visibilityState === 'visible').

Особые случаи на популярных движках

WordPress

Плохая новость: типичный коммерческий шаблон с парой комбайнов вёрстки на главной даёт INP 250-400 миллисекунд. Хорошая новость: главные источники известны.

Чек-лист:

  • Убрать неиспользуемые плагины. Хитрая правда: каждый активированный плагин это потенциальная нагрузка на каждой странице.
  • Отключить jQuery Migrate, если у вас тема и плагины с ним совместимы. Сегодня большинство совместимы.
  • Подключить плагин типа Perfmatters, Asset CleanUp или WP Rocket для выборочного отключения CSS и JS на страницах, где они не нужны.
  • Удалить устаревший Slider Revolution, если он сидит на главной без активного использования.
  • Проверить Visual Composer / WPBakery: они грузят CSS и JS, даже когда нет активных блоков.

Битрикс

В Битриксе INP проседает чаще на страницах каталога с фильтрацией. Стандартный компонент bitrix:catalog.smart.filter на больших каталогах ощутимо тормозит.

Решения:

  • Включить ajax-режим компонента, чтобы фильтр не перезагружал всю страницу.
  • На больших каталогах поставить серверный пагинатор и фильтр через GET-параметры, а не через клиентскую перерисовку.
  • Кешировать результаты фильтрации на уровне компонента.
  • Убрать неиспользуемые виджеты с главной (информер курсов, лента новостей, опросы), если на них не приходит клика регулярно.

Tilda

Tilda обычно даёт зелёный INP на статических страницах, но на главной с большим количеством T-блоков, особенно с галереями, INP может уезжать.

Решения:

  • Минимизировать количество подключённых внешних виджетов через T123.
  • Не злоупотреблять Zero Block с тяжёлой версткой.
  • Включить отложенную загрузку видеовставок.
Дашборд с графиком отклика по дням

Реалистичная цель и реалистичные сроки

Перевести типичный коммерческий WordPress-сайт из красного INP в жёлтый занимает примерно 8-16 часов работы: аудит, чистка плагинов, оптимизация скриптов, тесты. Перевод из жёлтого в зелёный это ещё 8-12 часов: переписывание частей кода или замена тяжёлых компонентов.

Сроки полевых данных: после правок CrUX обновляется за 4-7 дней, окончательная картина за 28 дней (это ширина окна агрегации). Не паникуйте, если PageSpeed первые сутки показывает старые цифры.

Если хотите делегировать эту работу, оптимизация INP входит в часовую ставку или в любой из тарифов на /#pricing. Аудит INP с конкретным списком правок можно заказать как разовую услугу через /#contact.

Дополнительные материалы по другим Core Web Vitals в разделе /blog/category/speed/, там есть отдельные статьи про LCP, CLS, шрифты, виджеты и виджеты JivoSite.

Частые вопросы

Чем INP отличается от FID

FID измерял задержку до реакции на первое действие. INP оценивает каждое нажатие за визит и берёт из них худшее. Сайт мог отвечать быстро на первый клик и тормозить на пятом, и FID этого не видел.

Какое значение INP считается хорошим

До 200 мс зелёная зона, от 200 до 500 требует внимания, выше плохо. В отчёт идёт значение, ниже которого укладываются 75 процентов нажатий у реальных посетителей.

Почему INP хуже у старых сайтов

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

Что даёт самый быстрый эффект

Убрать лишние скрипты со страниц, где они не нужны, разбить длинные задачи и отложить всё некритичное. Это работает лучше, чем вылизывание одного обработчика.

Передайте техническую часть в надёжные руки.

Слежу за хостингом, бэкапами и обновлениями. Когда что-то пойдёт не так – звоните мне, не своему программисту, не в спортзал и не маме.

Короткие вопросы по теме

Все вопросы по теме "Скорость сайта"

Заявка

Обсудим задачу

Напишите имя и телефон, выберите удобный канал. Перезвоню или напишу в течение часа в рабочее время.

Куда удобнее ответить?