Фронтенд2 хв читання

INP на практиці: як знайти й виправити повільні кліки

Interaction to Next Paint вимірює, скільки користувач чекає на реакцію сторінки. Показую, як виміряти INP у полі та розбити довгі задачі.

inp

Ілюстративне фото: Unsplash

З березня 2024 року Interaction to Next Paint — один із трьох Core Web Vitals, він замінив FID. Різниця принципова: FID вимірював лише затримку першої взаємодії, а INP дивиться на всі кліки, дотики й натискання клавіш за весь візит — і показує одну з найгірших.

Що саме вимірює INP

Кожна взаємодія складається з трьох частин. Повільною може бути будь-яка, тож спершу треба знати, яка саме.

  • Input delay — час, поки браузер узагалі почне обробляти подію, бо головний потік зайнятий чимось іншим.
  • Processing time — час виконання ваших обробників.
  • Presentation delay — перерахунок стилів, layout і малювання наступного кадру.
ОцінкаINP (75-й перцентиль)
Добре≤ 200 мс
Треба покращити200–500 мс
Погано> 500 мс

Вимірюйте в полі, а не лише в лабораторії

Lighthouse не клікає замість користувача, тому справжнього INP не покаже. Потрібні дані з реальних сесій. Найпростіше — бібліотека web-vitals зі збіркою attribution, яка одразу каже, який елемент і яка фаза підвели.

import { onINP } from 'web-vitals/attribution';

onINP(({ value, attribution }) => {
  const { interactionTarget, inputDelay, processingDuration, presentationDelay } = attribution;
  navigator.sendBeacon('/vitals', JSON.stringify({
    value, interactionTarget, inputDelay, processingDuration, presentationDelay,
  }));
});

Через тиждень збору зазвичай видно, що проблему створюють кілька конкретних елементів: фільтр у магазині, кнопка «у кошик», меню на телефоні.

Розбийте довгі задачі

Найчастіша причина поганого INP — обробник, який робить усе одразу: оновлює стан, перераховує список, шле аналітику. Браузер не може намалювати кадр, доки це не скінчиться. Рішення: одразу зробити те, що видно, а решту віддати частинами.

function yieldToMain() {
  if ('scheduler' in window && 'yield' in scheduler) return scheduler.yield();
  return new Promise((resolve) => setTimeout(resolve, 0));
}

button.addEventListener('click', async () => {
  showSpinner();            // користувач одразу бачить реакцію
  await yieldToMain();
  applyFilters();
  await yieldToMain();
  sendAnalytics();
});

Порада Панель Performance у Chrome DevTools тепер показує взаємодії на окремій доріжці й позначає ті, що довші за 200 мс. Запишіть клік і шукайте червоні трикутники.

Швидкі перемоги

  • Відкладіть сторонні скрипти (чат, теплові карти) до моменту після взаємодії або простою.
  • Зменште DOM — тисячі вузлів роблять кожен layout дорожчим.
  • Використовуйте content-visibility: auto для секцій нижче першого екрана.
  • Не читайте розміри (offsetHeight) одразу після зміни стилів у циклі — це змушує синхронний layout.

INP рідко виправляється однією зміною. Але зазвичай вистачає трьох-чотирьох влучних правок у найчастіше натискуваних місцях, щоб опуститися нижче 200 мс.

STOS

Блог про фронтенд, DevOps та інструменти

Зроблено на WordPress: власна блокова тема, Polylang, Yoast SEO. Подивитися адмінку WordPress у Playground ↗

STOS — вигаданий блог, концепт-проєкт для портфоліо. Авторка й тексти — приклади.