В марте 2024 года Google завершил переход от метрики FID (First Input Delay) к INP (Interaction to Next Paint) в наборе Core Web Vitals. Яндекс, который также ориентируется на Core Web Vitals при ранжировании, принял это изменение в своих инструментах. Если вы ещё не разобрались с INP — это статья для вас.
Что такое INP и чем он отличается от FID
FID: что было раньше
FID (First Input Delay) измерял только задержку первого взаимодействия пользователя со страницей — например, первого клика. И только задержку до начала обработки события, но не время полного выполнения.
Проблема FID: страница могла реагировать быстро на первый клик, но «зависать» при последующих взаимодействиях. FID это не улавливал.
INP: что пришло на замену
INP (Interaction to Next Paint) измеряет все взаимодействия пользователя со страницей на протяжении всего визита — клики, нажатия клавиш, тапы. И не только задержку до начала обработки, но всё время до следующей перерисовки экрана (next paint): обработку события + обновление DOM + рендеринг.
Итоговое значение INP — это 98-й перцентиль среди всех взаимодействий за сессию (фактически: самое медленное взаимодействие, не считая единичных аномалий).
Пороговые значения INP
- < 200 мс — хорошо
- 200–500 мс — требует улучшения
- > 500 мс — плохо
Почему INP важен для SEO
Официальный фактор ранжирования
Core Web Vitals, включая INP, являются сигналом Page Experience, который учитывается Google при ранжировании. Яндекс также декларирует учёт скорости и удобства страниц.
Влияние на конверсии
Медленный отклик страницы напрямую влияет на поведение пользователей. Исследования показывают, что каждые 100 мс задержки отклика снижают конверсию на 1–7% в зависимости от типа взаимодействия. Для e-commerce — это прямые потери дохода.
Поведенческие факторы
Яндекс учитывает поведенческие сигналы: если пользователи уходят с сайта из-за «залипающего» интерфейса — это негативный сигнал для ранжирования. INP — технический коррелят этого поведения.
Для отслеживания связи INP с поведенческими метриками и позициями используют SEO-платформы вроде ClickFlow, которые агрегируют данные Core Web Vitals с данными о видимости в поиске.
Как измерить INP
Инструменты
Chrome UX Report (CrUX) — реальные данные о INP от реальных пользователей Chrome. Это именно те данные, которые используют поисковики.
PageSpeed Insights — показывает INP из CrUX (если данных достаточно) и лабораторную оценку через Lighthouse.
Search Console — раздел Core Web Vitals, агрегированные данные по страницам с разбивкой на мобильные/десктоп.
Яндекс Вебмастер → «Качество сайта» — показывает INP для вашего сайта.
Chrome DevTools → Performance — вкладка Interactions показывает INP для конкретных взаимодействий в реальном времени.
Web Vitals Library (JavaScript):
import { onINP } from 'web-vitals';
onINP(({ value, rating }) => {
console.log(`INP: ${value}ms (${rating})`);
});
Важность полевых данных
INP нельзя полностью воспроизвести в лабораторных условиях — он зависит от реального поведения пользователей. Лабораторные инструменты (Lighthouse) дают лишь ориентир.
Анатомия INP: из чего складывается задержка
Время INP = Input Delay + Processing Time + Presentation Delay
Input Delay (задержка ввода) — время от действия пользователя до начала обработки события. Главная причина: основной поток занят выполнением другого кода (длинные задачи).
Processing Time (время обработки) — выполнение обработчиков событий (JavaScript). Если обработчик выполняется 300 мс — это проблема.
Presentation Delay (задержка отображения) — время рендеринга после обновления DOM: style calculation, layout, paint, composite.
Причины плохого INP и способы устранения
1. Длинные задачи (Long Tasks) в основном потоке
Длинные задачи — это блоки JavaScript, выполняющиеся дольше 50 мс. Пока выполняется длинная задача, браузер не может обработать пользовательский ввод — отсюда высокий Input Delay.
Диагностика: Chrome DevTools → Performance → длинные задачи отображаются красным треугольником.
Решения:
Разбивка длинных задач на части через scheduler.yield() или setTimeout:
async function processLargeArray(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// Уступаем управление браузеру каждые 50 элементов
if (i % 50 === 0) {
await scheduler.yield();
}
}
}
Web Workers — выносим тяжёлые вычисления в отдельный поток:
const worker = new Worker('heavy-task.js');
worker.postMessage({ data: largeData });
worker.onmessage = (e) => updateUI(e.data);
2. Неэффективные обработчики событий
Если обработчик клика делает слишком много работы синхронно — Processing Time растёт.
Принцип: обработчик должен делать только необходимый минимум. Остальное — в requestAnimationFrame или асинхронно:
button.addEventListener('click', (e) => {
// Только срочное обновление UI — синхронно
updateButtonState(e.target);
// Тяжёлую работу — откладываем
requestAnimationFrame(() => {
expensiveUpdate();
});
});
3. Избыточные перерасчёты макета (Layout Thrashing)
Чередование чтения и записи DOM-свойств вызывает принудительные синхронные перерасчёты layout:
// Плохо: каждый вызов offsetHeight вызывает layout
elements.forEach(el => {
const height = el.offsetHeight; // Чтение → layout
el.style.height = height * 2 + 'px'; // Запись → invalidate
});
// Хорошо: сначала читаем всё, потом пишем
const heights = elements.map(el => el.offsetHeight); // Все чтения
elements.forEach((el, i) => {
el.style.height = heights[i] * 2 + 'px'; // Все записи
});
Библиотека FastDOM автоматизирует это разделение.
4. Тяжёлые сторонние скрипты
Аналитика, A/B тесты, пиксели и виджеты часто выполняют тяжёлый JavaScript. Они конкурируют с основным кодом за время основного потока.
Решения:
- Загружать сторонние скрипты только после загрузки страницы (
defer, или черезloadevent) - Использовать Partytown — библиотека, переносящая сторонние скрипты в Web Worker
- Аудит необходимости каждого стороннего скрипта
5. Слишком сложный DOM
Большой DOM (более 1500 элементов) замедляет все операции с ним: поиск, обновление, рендеринг. Presentation Delay растёт.
Решения:
- Виртуализация списков (react-virtual, vue-virtual-scroller) — рендерим только видимые элементы
- Разбивка на компоненты с ленивой загрузкой
- Удаление скрытых, но не удалённых из DOM элементов
6. Неоптимальные CSS-переходы
CSS-анимации, использующие свойства box-shadow, filter, border-radius на большой площади — дорогостоящие для рендеринга.
Предпочитайте transform и opacity:
/* Дорого */
.card:hover { box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
/* Дёшево — только composite layer */
.card { transition: transform 0.2s, opacity 0.2s; }
.card:hover { transform: translateY(-4px); }
INP и React/Vue/Angular
SPA-фреймворки особенно уязвимы для плохого INP. Большие обновления состояния перерисовывают много компонентов одновременно.
React 18+: используйте startTransition для не-срочных обновлений:
import { startTransition } from 'react';
function handleFilter(value) {
// Срочно: показать значение в поле ввода
setInputValue(value);
// Не срочно: фильтрация списка
startTransition(() => {
setFilteredList(filterItems(items, value));
});
}
Мемоизация — React.memo, useMemo, useCallback предотвращают лишние перерендеры.
Чек-лист улучшения INP
- [ ] INP измерен через PageSpeed Insights и Яндекс Вебмастер
- [ ] Long Tasks выявлены через Chrome DevTools
- [ ] Длинные задачи разбиты через scheduler.yield() или setTimeout
- [ ] Тяжёлые вычисления вынесены в Web Workers
- [ ] Обработчики событий не выполняют синхронную тяжёлую работу
- [ ] Layout Thrashing устранён (чтение и запись DOM разделены)
- [ ] Сторонние скрипты загружаются после load event
- [ ] DOM не превышает 1500 элементов на странице
- [ ] CSS-анимации используют transform и opacity
- [ ] Для React — применён startTransition и мемоизация
- [ ] Мониторинг INP настроен через Web Vitals API
Итог
INP — наиболее комплексная метрика из набора Core Web Vitals. Она измеряет не просто один момент в жизни страницы, а всю интерактивность за визит. Улучшение INP требует глубокого анализа JavaScript-производительности, оптимизации обработчиков событий и работы с основным потоком. Результат оправдывает усилия: быстрый отклик интерфейса напрямую повышает конверсию и улучшает позиции в поиске.