---
title: "INP vs FID: Nowa metryka interaktywności w Core Web Vitals"
description: "Interaction to Next Paint (INP) zastąpiło FID jako metrykę Core Web Vitals. Poznaj różnice, jak mierzyć INP i jak optymalizować responsywność strony."
date: 2025-12-30
category: Optymalizacja
tags: ["Core Web Vitals", "INP", "FID", "Performance", "SEO", "JavaScript"]
url: https://uper.pl/blog/inp-vs-fid/
---

# INP vs FID: Nowa metryka interaktywności w Core Web Vitals

W marcu 2024 roku Google oficjalnie zastąpił **First Input Delay (FID)** nową metryką **Interaction to Next Paint (INP)** jako część [Core Web Vitals](/blog/core-web-vitals/). INP lepiej odzwierciedla rzeczywistą responsywność strony i jest trudniejsza do optymalizacji. Ten przewodnik wyjaśnia różnice i pokazuje jak poprawić wyniki.

## Czym było FID?

**First Input Delay** mierzył czas od pierwszej interakcji użytkownika (kliknięcie, tap) do momentu, gdy przeglądarka mogła rozpocząć obsługę tego zdarzenia. Mierzył tylko **pierwszą** interakcję.

### Ograniczenia FID

1. **Tylko pierwsza interakcja** - ignorował wszystkie kolejne
2. **Tylko opóźnienie** - nie mierzył czasu przetwarzania
3. **Łatwy do optymalizacji** - wystarczyło szybkie pierwsze ładowanie
4. **Nie odzwierciedlał rzeczywistości** - strona mogła być wolna po pierwszej interakcji

## Czym jest INP?

**Interaction to Next Paint** mierzy responsywność strony przez cały czas jej użytkowania. Bierze pod uwagę wszystkie interakcje (kliknięcia, tappy, naciśnięcia klawiszy) i raportuje najgorszą z nich (technicznie: 98. percentyl).

### Co mierzy INP?

INP mierzy czas od interakcji do momentu wyrenderowania następnej klatki:

```
INP = Input Delay + Processing Time + Presentation Delay
```

1. **Input Delay** - czas oczekiwania na rozpoczęcie obsługi (jak FID)
2. **Processing Time** - czas wykonania event handlerów
3. **Presentation Delay** - czas renderowania zmian w DOM

### Progi INP

| Wynik | Ocena |
|-------|-------|
| ≤ 200ms | **Dobry** (zielony) |
| 200ms - 500ms | **Wymaga poprawy** (pomarańczowy) |
| > 500ms | **Słaby** (czerwony) |

## Porównanie FID vs INP

| Aspekt | FID | INP |
|--------|-----|-----|
| Co mierzy | Tylko opóźnienie | Opóźnienie + przetwarzanie + renderowanie |
| Które interakcje | Tylko pierwszą | Wszystkie (raportuje najgorszą) |
| Progi | ≤100ms dobry | ≤200ms dobry |
| Trudność optymalizacji | Niska | Wysoka |
| Status | Wycofany (marzec 2024) | Aktualny Core Web Vital |

## Jak mierzyć INP?

### Dane laboratoryjne

**Lighthouse (Chrome DevTools):**
- INP nie jest bezpośrednio mierzony w Lighthouse
- Użyj **Total Blocking Time (TBT)** jako proxy

**Chrome DevTools - Performance:**
1. Otwórz Performance panel
2. Nagrywaj podczas interakcji z stroną
3. Szukaj długich tasków w Main thread

### Dane rzeczywiste (Field data)

**web-vitals library:**

```javascript

onINP((metric) => {
  console.log('INP:', metric.value);
  console.log('Rating:', metric.rating); // good, needs-improvement, poor
  console.log('Entries:', metric.entries); // Szczegóły interakcji
});
```

**Google Search Console:**
- Core Web Vitals report pokazuje INP z danych CrUX

**PageSpeed Insights:**
- Sekcja "Diagnoza problemów z wydajnością" pokazuje INP

### Chrome DevTools - Web Vitals overlay

1. Otwórz DevTools
2. Naciśnij **Ctrl+Shift+P**
3. Wpisz "Show Web Vitals"
4. Interakcja ze stroną pokaże INP w czasie rzeczywistym

## Przyczyny słabego INP

### 1. Długie taski JavaScript

JavaScript blokuje main thread. Każdy task >50ms to "long task" wpływający na INP.

```javascript
// Źle - długi synchroniczny task
function processData(items) {
  items.forEach(item => {
    // Ciężkie obliczenia...
    heavyComputation(item);
  });
}

// Dobrze - podziel na mniejsze taski
async function processDataAsync(items) {
  for (const item of items) {
    heavyComputation(item);
    // Oddaj kontrolę przeglądarce
    await scheduler.yield();
  }
}

// Alternatywnie z setTimeout
function processDataChunked(items, chunkSize = 10) {
  let index = 0;

  function processChunk() {
    const chunk = items.slice(index, index + chunkSize);
    chunk.forEach(heavyComputation);
    index += chunkSize;

    if (index < items.length) {
      setTimeout(processChunk, 0);
    }
  }

  processChunk();
}
```

### 2. Ciężkie event handlery

```javascript
// Źle - ciężki handler blokuje rendering
button.addEventListener('click', () => {
  // 500ms obliczeń...
  processLargeDataset();
  updateUI();
});

// Dobrze - oddziel obliczenia od UI
button.addEventListener('click', async () => {
  // Natychmiast pokaż feedback
  button.disabled = true;
  showSpinner();

  // Obliczenia w następnym tasku
  await scheduler.yield();
  const result = processLargeDataset();

  // Update UI
  await scheduler.yield();
  updateUI(result);
  hideSpinner();
  button.disabled = false;
});
```

### 3. Zbyt wiele re-renderów

```javascript
// Źle - każda zmiana triggeruje reflow
items.forEach(item => {
  const div = document.createElement('div');
  div.textContent = item.name;
  container.appendChild(div); // Reflow!
});

// Dobrze - batch DOM operations
const fragment = document.createDocumentFragment();
items.forEach(item => {
  const div = document.createElement('div');
  div.textContent = item.name;
  fragment.appendChild(div);
});
container.appendChild(fragment); // Jeden reflow
```

### 4. Layout thrashing

```javascript
// Źle - wielokrotne odczyty i zapisy
elements.forEach(el => {
  const height = el.offsetHeight; // Odczyt (force layout)
  el.style.height = height + 10 + 'px'; // Zapis (invalidate layout)
});

// Dobrze - najpierw odczytaj, potem zapisz
const heights = elements.map(el => el.offsetHeight);
elements.forEach((el, i) => {
  el.style.height = heights[i] + 10 + 'px';
});
```

### 5. Third-party scripts

Skrypty firm trzecich (analytics, ads, chat widgets) często mają ciężkie handlery.

## Techniki optymalizacji INP

### 1. Scheduler API (scheduler.yield)

Nowe API pozwalające oddać kontrolę przeglądarce:

```javascript
async function handleClick() {
  // Krok 1
  await scheduler.yield();

  // Krok 2
  await scheduler.yield();

  // Krok 3
}

// Polyfill dla starszych przeglądarek
if (!('scheduler' in window)) {
  window.scheduler = {
    yield: () => new Promise(resolve => setTimeout(resolve, 0))
  };
}
```

### 2. requestIdleCallback

Wykonuj mniej pilne taski gdy przeglądarka jest idle:

```javascript
// Przetwarzanie w tle
function processInBackground(items) {
  let index = 0;

  function processNext(deadline) {
    while (index < items.length && deadline.timeRemaining() > 0) {
      processItem(items[index]);
      index++;
    }

    if (index < items.length) {
      requestIdleCallback(processNext);
    }
  }

  requestIdleCallback(processNext);
}
```

### 3. requestAnimationFrame

Synchronizuj zmiany wizualne z frame rate:

```javascript
// Źle - może trafić w środek frame
button.addEventListener('click', () => {
  element.style.transform = 'translateX(100px)';
});

// Dobrze - synchronizacja z frame
button.addEventListener('click', () => {
  requestAnimationFrame(() => {
    element.style.transform = 'translateX(100px)';
  });
});
```

### 4. Web Workers

Przenieś ciężkie obliczenia poza main thread:

```javascript
// main.js
const worker = new Worker('worker.js');

button.addEventListener('click', () => {
  showSpinner();
  worker.postMessage({ data: largeDataset });
});

worker.onmessage = (e) => {
  hideSpinner();
  displayResults(e.data);
};

// worker.js
self.onmessage = (e) => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};
```

### 5. Debouncing i throttling

```javascript
// Debounce - wykonaj po zakończeniu sekwencji
function debounce(fn, delay) {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn(...args), delay);
  };
}

// Throttle - wykonuj maksymalnie raz na X ms
function throttle(fn, limit) {
  let inThrottle;
  return (...args) => {
    if (!inThrottle) {
      fn(...args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// Użycie
input.addEventListener('input', debounce(handleSearch, 300));
window.addEventListener('scroll', throttle(handleScroll, 100));
```

### 6. Passive event listeners

```javascript
// Źle - może blokować scrollowanie
element.addEventListener('touchstart', handler);

// Dobrze - deklaracja że nie będzie preventDefault
element.addEventListener('touchstart', handler, { passive: true });
```

### 7. CSS contain

Ogranicz obszar, który musi być przeliczony:

```css
.widget {
  contain: content; /* Izoluje layout i paint */
}

.modal {
  contain: strict; /* Pełna izolacja */
}
```

### 8. content-visibility

Opóźnij renderowanie elementów poza viewport:

```css
.card {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px; /* Szacowana wysokość */
}
```

## Optymalizacja frameworków

### React

```jsx
// Użyj startTransition dla mniej pilnych aktualizacji

function handleClick() {
  // Pilna aktualizacja - natychmiast
  setIsLoading(true);

  // Mniej pilna - może być odroczona
  startTransition(() => {
    setResults(computeExpensiveResults());
  });
}

// useDeferredValue dla drogich renderów

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);

  // Renderuj z opóźnionym query
  return <Results query={deferredQuery} />;
}

// memo dla unikania zbędnych re-renderów
const ExpensiveComponent = React.memo(({ data }) => {
  // ...
});
```

### Vue

```vue
<script setup>

// shallowRef dla dużych obiektów
const largeData = shallowRef(null);

// Lazy computed
const expensiveComputed = computed(() => {
  // Obliczenia tylko gdy potrzebne
});
</script>

<template>
  <!-- v-once dla statycznej treści -->
  <div v-once>{{ staticContent }}</div>

  <!-- v-memo dla cachowania -->
  <div v-for="item in list" :key="item.id" v-memo="[item.id]">
    {{ item.name }}
  </div>
</template>
```

## Checklist optymalizacji INP

### JavaScript
- [ ] Podziel długie taski na mniejsze (poniżej 50ms)
- [ ] Użyj scheduler.yield() lub setTimeout(0)
- [ ] Przenieś ciężkie obliczenia do Web Workers
- [ ] Debounce/throttle event handlerów

### DOM
- [ ] Batch DOM operations (DocumentFragment)
- [ ] Unikaj layout thrashing
- [ ] Użyj requestAnimationFrame dla animacji
- [ ] Zastosuj CSS contain dla izolacji

### Third-party
- [ ] Defer nieistotne skrypty
- [ ] Lazy-load widgety (chat, social)
- [ ] Rozważ [server-side GTM](/blog/gtm-server-side-vs-client-side/)

### Framework
- [ ] React: startTransition, useDeferredValue
- [ ] Vue: v-once, v-memo, shallowRef
- [ ] Virtualizacja długich list

## Monitorowanie INP

### Real User Monitoring (RUM)

```javascript

onINP((metric) => {
  // Wyślij do analytics
  gtag('event', 'web_vitals', {
    metric_name: metric.name,
    metric_value: metric.value,
    metric_rating: metric.rating,
    metric_delta: metric.delta
  });

  // Lub do własnego endpointa
  navigator.sendBeacon('/analytics', JSON.stringify({
    name: 'INP',
    value: metric.value,
    page: location.pathname
  }));
});
```

### Alerty na słabe INP

Ustaw alerty w Google Search Console lub własnym systemie monitoringu gdy INP przekroczy próg.

## Podsumowanie

**INP** jest trudniejszą metryką niż FID, ale lepiej odzwierciedla rzeczywiste doświadczenie użytkownika. Responsywność interakcji to kluczowy aspekt SXO — sprawdź go w ramach [kompleksowego audytu SEO i UX](/audyt-sxo/). Kluczowe punkty:

1. **INP mierzy całą interakcję** - nie tylko opóźnienie
2. **Raportuje najgorszą interakcję** - musisz optymalizować wszystko
3. **Podziel długie taski** - żaden task nie powinien trwać >50ms
4. **Oddawaj kontrolę przeglądarce** - scheduler.yield(), requestIdleCallback
5. **Web Workers** - dla ciężkich obliczeń
6. **Monitoruj w RUM** - dane laboratoryjne nie wystarczą

Cel to **INP poniżej 200ms** dla 75% użytkowników.

Więcej o tym, jak INP i pozostałe metryki wydajności wpływają na ranking w Google, znajdziesz w [przewodniku po technologiach web i SEO](/blog/technologie-web-seo-ranking-google/).

## Źródła

1. **web.dev - Interaction to Next Paint (INP)**
[https://web.dev/articles/inp](https://web.dev/articles/inp)

2. **web.dev - Optimize INP**
[https://web.dev/articles/optimize-inp](https://web.dev/articles/optimize-inp)

3. **Chrome Developers - INP announcement**
[https://developer.chrome.com/blog/inp-cwv](https://developer.chrome.com/blog/inp-cwv)

4. **web.dev - Long tasks**
[https://web.dev/articles/optimize-long-tasks](https://web.dev/articles/optimize-long-tasks)

5. **MDN - Scheduler API**
[https://developer.mozilla.org/en-US/docs/Web/API/Scheduler](https://developer.mozilla.org/en-US/docs/Web/API/Scheduler)

6. **web.dev - First Input Delay (FID) - archived**
[https://web.dev/articles/fid](https://web.dev/articles/fid)
