Optimalizácia INP: Kompletný sprievodca rýchlou odozvou webu v roku 2026

INP je najčastejšie zlyhávaná metrika Core Web Vitals — 43 % webov prekračuje hranicu 200 ms. Naučte sa diagnostikovať pomalé interakcie pomocou LoAF API, rozdeľovať dlhé úlohy cez scheduler.yield(), presúvať prácu do Web Workers a využívať concurrent features React, Vue a Angular.

Prečo je INP najdôležitejšia metrika webového výkonu v roku 2026

V predchádzajúcich článkoch sme sa venovali optimalizácii obrázkov, navigácie, doručovania kódu a cachovania. Teraz prichádza na rad piaty — a úprimne povedané, možno najkritickejší — pilier: odozva na interakciu používateľa. Metrika Interaction to Next Paint (INP) meria, ako rýchlo vaša stránka vizuálne reaguje na kliknutia, ťuknutia a stlačenia klávesov. A práve tu sa v roku 2026 lámu Core Web Vitals najviac.

INP nahradila metriku First Input Delay (FID) ako oficiálny Core Web Vital v marci 2024. Rozdiel je zásadný — FID merala iba oneskorenie pred prvou interakciou, zatiaľ čo INP zachytáva všetky interakcie počas celého života stránky a reportuje hodnotu na 75. percentile. Podľa aktuálnych dát 43 % webov stále prekračuje hranicu 200 ms, čo z INP robí najčastejšie zlyhávanú metriku Core Web Vitals.

Marcová aktualizácia jadra Google v roku 2026 ešte viac posilnila váhu INP ako rankingového signálu. Weby s INP nad 200 ms zaznamenali priemerný pokles o 0,8 pozície v organickom vyhľadávaní. A weby nad 500 ms? Tie stratili 2 až 4 pozície na konkurenčných dotazoch. Tak poďme na to — v tomto článku si prejdeme všetko, čo potrebujete vedieť na dosiahnutie INP pod 200 ms.

Tri fázy INP: Kde sa stráca čas

Každá interakcia na vašej stránke prechádza tromi fázami a INP je súčtom všetkých troch. Pochopenie týchto fáz je kľúčové, pretože vám prezradí, kde presne máte problém:

  • Input Delay (vstupné oneskorenie) — čas od momentu, keď používateľ klikne alebo ťukne, po začiatok vykonávania event handlera. Vzniká, keď hlavné vlákno prehliadača spracováva inú úlohu a nemôže okamžite reagovať. Zaujímavé je, že interakcie počas načítavania stránky majú priemernú input delay 132 ms oproti 50 ms po dokončení načítania — teda 2,6-násobný rozdiel.
  • Processing Time (čas spracovania) — čas strávený vykonávaním vašich JavaScript event handlerov. Zahŕňa logiku v onClick, onChange a ďalších callbackoch vrátane akejkoľvek synchronnej práce v rámci nich.
  • Presentation Delay (oneskorenie vykreslenia) — čas od dokončenia event handlerov po vykreslenie ďalšieho frame. Zahŕňa prepočítanie štýlov, layout, compositing a paint. Veľký DOM túto fázu výrazne predlžuje (a to je téma, ku ktorej sa ešte vrátime).

Cieľ je jasný: súčet všetkých troch fáz musí byť pod 200 ms pre 75 % interakcií vašich skutočných používateľov. Hodnoty 200–500 ms Google hodnotí ako „potrebuje zlepšenie" a nad 500 ms ako „zlé".

Diagnostika: Ako nájsť najpomalšie interakcie

Pred optimalizáciou musíte vedieť, ktoré interakcie sú pomalé a prečo. INP reportuje najhoršiu interakciu na stránke (alebo 98. percentil pri stránkach s 50+ interakciami), takže jedna jediná pomalá interakcia vám dokáže zhoršiť celé skóre.

Meranie v teréne pomocou knižnice web-vitals

Najspoľahlivejšie dáta pochádzajú od skutočných používateľov. Knižnica web-vitals od Google poskytuje attribution build, ktorý presne identifikuje problematickú interakciu:

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

onINP((metric) => {
  const { value, attribution } = metric;
  const {
    interactionTarget,
    interactionType,
    inputDelay,
    processingDuration,
    presentationDelay,
    longAnimationFrameEntries,
  } = attribution;

  console.log(`INP: ${value}ms`);
  console.log(`Element: ${interactionTarget}`);
  console.log(`Typ: ${interactionType}`);
  console.log(`Input Delay: ${inputDelay}ms`);
  console.log(`Processing: ${processingDuration}ms`);
  console.log(`Presentation: ${presentationDelay}ms`);

  // LoAF skripty, ktoré prispeli k pomalej interakcii
  longAnimationFrameEntries?.forEach((loaf) => {
    loaf.scripts?.forEach((script) => {
      console.log(`Skript: ${script.sourceURL}`);
      console.log(`Trvanie: ${script.duration}ms`);
      console.log(`Typ: ${script.invokerType}`);
    });
  });

  // Odošlite dáta do vášho analytics nástroja
  sendToAnalytics({
    name: "INP",
    value,
    target: interactionTarget,
    inputDelay,
    processingDuration,
    presentationDelay,
  });
}, { reportAllChanges: true });

Long Animation Frames (LoAF) API

LoAF API je skutočne výkonný diagnostický nástroj — dostupný v prehliadačoch založených na Chromium od verzie 123. Na rozdiel od staršieho Long Tasks API (ktoré vám povedalo len "niečo bolo pomalé"), LoAF poskytuje detailnú atribúciu. Presne viete, ktorý skript, ktorá funkcia a ktorá fáza renderingu spôsobila spomalenie:

// Sledovanie dlhých animačných rámcov
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Celkové trvanie rámca
    console.log(`LoAF trvanie: ${entry.duration}ms`);
    console.log(`Blokovanie: ${entry.blockingDuration}ms`);
    console.log(`Render začiatok: ${entry.renderStart}ms`);

    // Detailná atribúcia skriptov
    entry.scripts.forEach((script) => {
      console.log(`  Zdroj: ${script.sourceURL}`);
      console.log(`  Funkcia: ${script.sourceFunctionName}`);
      console.log(`  Typ: ${script.invokerType}`);
      console.log(`  Trvanie: ${script.duration}ms`);
      console.log(`  Nútený layout: ${script.forcedStyleAndLayoutDuration}ms`);
    });
  }
});

// Feature detection pred použitím
if (PerformanceObserver.supportedEntryTypes.includes("long-animation-frame")) {
  observer.observe({ type: "long-animation-frame", buffered: true });
}

Dôležité: LoAF API je zatiaľ podporované iba v Chrome a prehliadačoch založených na Chromium. Firefox a Safari ho zatiaľ nepodporujú, ale štandardizácia prebieha cez W3C — takže sa to v budúcnosti zmení.

Chrome DevTools Performance panel

Pre lokálnu diagnostiku otvorte Chrome DevTools, prejdite na záložku Performance a nahrajte interakciu. DevTools vám zobrazia timeline s jednotlivými úlohami na hlavnom vlákne. Hľadajte červené značky „Long Task" — akákoľvek úloha dlhšia ako 50 ms blokuje spracovanie interakcií. Kliknutím na úlohu uvidíte call stack a presne identifikujete, ktorý kód je vinníkom.

Rozdelenie dlhých úloh: Základná technika zlepšenia INP

Najčastejšou príčinou zlého INP sú dlhé JavaScript úlohy, ktoré blokujú hlavné vlákno. Akákoľvek úloha trvajúca viac ako 50 ms bráni prehliadaču reagovať na používateľské vstupy. Riešenie je v podstate jednoduché — rozdeliť prácu na menšie časti a medzi nimi dať prehliadaču priestor na spracovanie interakcií.

scheduler.yield() — moderný prístup

API scheduler.yield() je podľa mňa najelegantnejší spôsob rozdelenia dlhých úloh. Na rozdiel od setTimeout zaručuje, že pokračovanie vašej práce bude mať prioritu pred inými čakajúcimi úlohami — neutrpíte teda zbytočné oneskorenie:

// Spracovanie veľkého zoznamu bez blokovania hlavného vlákna
async function processLargeList(items) {
  const BATCH_SIZE = 50;
  const results = [];

  for (let i = 0; i < items.length; i += BATCH_SIZE) {
    const batch = items.slice(i, i + BATCH_SIZE);
    results.push(...batch.map(processItem));

    // Yield po každej dávke — prehliadač spracuje čakajúce interakcie
    if (i + BATCH_SIZE < items.length) {
      await scheduler.yield();
    }
  }

  return results;
}

// Fallback pre prehliadače bez podpory scheduler.yield
function yieldToMain() {
  if ("scheduler" in globalThis && "yield" in scheduler) {
    return scheduler.yield();
  }
  // setTimeout fallback — funguje všade, ale bez prioritizácie
  return new Promise((resolve) => setTimeout(resolve, 0));
}

// Univerzálna verzia s fallbackom
async function processLargeListSafe(items) {
  const BATCH_SIZE = 50;
  const results = [];

  for (let i = 0; i < items.length; i += BATCH_SIZE) {
    const batch = items.slice(i, i + BATCH_SIZE);
    results.push(...batch.map(processItem));

    if (i + BATCH_SIZE < items.length) {
      await yieldToMain();
    }
  }

  return results;
}

Podpora prehliadačov: scheduler.yield() je podporovaný v Chrome od roku 2024 a vo Firefoxe od augusta 2025. Safari ho zatiaľ nepodporuje — pre plnú kompatibilitu používajte polyfill scheduler-polyfill alebo fallback cez setTimeout.

Kedy yieldiť: Pravidlo 50 ms

Nemusíte yieldiť po každej jednotlivej operácii — to by pridalo zbytočnú réžiu. Ideálny prístup je yieldiť vtedy, keď od posledného yieldu uplynulo viac ako 50 ms. Je to jednoduchý, ale účinný vzor:

async function processWithTimeBudget(items) {
  let lastYield = performance.now();
  const results = [];

  for (const item of items) {
    results.push(processItem(item));

    // Yield iba ak sme prekročili 50 ms rozpočet
    if (performance.now() - lastYield > 50) {
      await yieldToMain();
      lastYield = performance.now();
    }
  }

  return results;
}

Web Workers: Presunutie ťažkej práce mimo hlavné vlákno

Niektoré operácie sú jednoducho príliš výpočtovo náročné na to, aby bežali na hlavnom vlákne — aj keď ich rozdelíte na menšie časti. Kryptografia, parsovanie veľkých JSON súborov, spracovanie obrázkov alebo komplexné výpočty? Tie patria do Web Workera:

// worker.js — beží v samostatnom vlákne
self.addEventListener("message", (event) => {
  const { type, data } = event.data;

  switch (type) {
    case "sort": {
      // Zoradenie 100 000+ položiek neblokuje hlavné vlákno
      const sorted = data.sort((a, b) => a.price - b.price);
      self.postMessage({ type: "sorted", result: sorted });
      break;
    }
    case "filter": {
      const filtered = data.filter((item) =>
        item.name.toLowerCase().includes(event.data.query.toLowerCase())
      );
      self.postMessage({ type: "filtered", result: filtered });
      break;
    }
  }
});

// main.js — hlavné vlákno zostáva voľné
const worker = new Worker("/worker.js");

function sortProducts(products) {
  return new Promise((resolve) => {
    worker.addEventListener(
      "message",
      (e) => {
        if (e.data.type === "sorted") resolve(e.data.result);
      },
      { once: true }
    );
    worker.postMessage({ type: "sort", data: products });
  });
}

// Použitie — kliknutie na "Zoradiť" nespôsobí zamrznutie UI
document.querySelector("#sort-btn").addEventListener("click", async () => {
  const sorted = await sortProducts(products);
  renderProductList(sorted); // Rýchly DOM update
});

Comlink: Jednoduchšia komunikácia s Web Workers

Ak vám tá manuálna komunikácia cez postMessage príde trochu ťažkopádna, nie ste sami. Knižnica comlink od Google eliminuje boilerplate kód a namiesto posielania správ voláte funkcie Workera, ako keby boli lokálne:

// worker.js s Comlink
import * as Comlink from "comlink";

const api = {
  async sortProducts(products) {
    return products.sort((a, b) => a.price - b.price);
  },
  async filterProducts(products, query) {
    return products.filter((item) =>
      item.name.toLowerCase().includes(query.toLowerCase())
    );
  },
};

Comlink.expose(api);

// main.js — volanie Worker funkcií ako bežných async funkcií
import * as Comlink from "comlink";

const worker = new Worker("/worker.js", { type: "module" });
const api = Comlink.wrap(worker);

document.querySelector("#sort-btn").addEventListener("click", async () => {
  const sorted = await api.sortProducts(products);
  renderProductList(sorted);
});

Optimalizácia event handlerov

Event handlery sú často hlavnou príčinou dlhého processing time. Tu sú overené techniky na ich zrýchlenie.

Debouncing a throttling

Udalosti ako scroll, resize a input sa môžu vyvolať stokrát za sekundu. Bez obmedzenia frekvencie každé vyvolanie spúšťa event handler a blokuje hlavné vlákno. To rozhodne nechcete:

// Debounce — spustí funkciu až po tom, čo používateľ prestane písať
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// Throttle — spustí funkciu maximálne raz za daný interval
function throttle(fn, interval) {
  let lastTime = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastTime >= interval) {
      lastTime = now;
      fn(...args);
    }
  };
}

// Použitie pri vyhľadávaní
const searchInput = document.querySelector("#search");
searchInput.addEventListener(
  "input",
  debounce((e) => {
    performSearch(e.target.value);
  }, 300)
);

// Použitie pri scrolle — passive listener pre lepší výkon
window.addEventListener(
  "scroll",
  throttle(() => {
    updateScrollIndicator();
  }, 100),
  { passive: true }
);

Vyhýbanie sa layout thrashingu

Layout thrashing je niečo, na čo sa ľahko narazí a ťažko sa identifikuje. Nastáva, keď JavaScript opakovane číta a zapisuje layoutové vlastnosti, čo núti prehliadač prepočítať layout pri každom čítaní. Výsledok? Prehliadač robí tú istú prácu stokrát namiesto raz:

// ZLE — layout thrashing (núti prehliadač prepočítať layout 100x)
function resizeCards(cards) {
  cards.forEach((card) => {
    const width = card.offsetWidth; // ČÍTANIE → vynútený layout
    card.style.height = width * 0.75 + "px"; // ZÁPIS → invaliduje layout
  });
}

// DOBRE — batch read, potom batch write
function resizeCards(cards) {
  // Najprv prečítame všetky hodnoty
  const widths = cards.map((card) => card.offsetWidth);

  // Potom zapíšeme všetky hodnoty naraz
  cards.forEach((card, i) => {
    card.style.height = widths[i] * 0.75 + "px";
  });
}

// NAJLEPŠIE — requestAnimationFrame pre odloženie zápisov
function resizeCards(cards) {
  const widths = cards.map((card) => card.offsetWidth);

  requestAnimationFrame(() => {
    cards.forEach((card, i) => {
      card.style.height = widths[i] * 0.75 + "px";
    });
  });
}

Optimalizácia INP v React aplikáciách

React aplikácie sú obzvlášť náchylné na zlé INP, pretože synchronné re-rendery môžu blokovať hlavné vlákno na stovky milisekúnd. Našťastie, React 18+ ponúka concurrent features, ktoré tento problém riešia pomerne elegantne.

useTransition — odloženie nekritických aktualizácií

Hook useTransition označí stavovú aktualizáciu ako nekritickú. React uprednostní okamžitú odozvu UI (napríklad aktualizáciu textového poľa) a náročný re-render vykoná na pozadí:

import { useState, useTransition } from "react";

function ProductFilter({ products }) {
  const [query, setQuery] = useState("");
  const [filtered, setFiltered] = useState(products);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const value = e.target.value;
    // Vysoká priorita — input reaguje okamžite
    setQuery(value);

    // Nízka priorita — filtrovanie prebehne na pozadí
    startTransition(() => {
      setFiltered(
        products.filter((p) =>
          p.name.toLowerCase().includes(value.toLowerCase())
        )
      );
    });
  };

  return (
    <div>
      <input value={query} onChange={handleChange} placeholder="Hľadať..." />
      {isPending && <div className="spinner" />}
      <ProductList products={filtered} />
    </div>
  );
}

useDeferredValue — odloženie hodnoty pre pomalé komponenty

Keď nemáte kontrolu nad stavovou aktualizáciou (napríklad prijímate props od rodiča), použite useDeferredValue. React vytvorí „zastaranú" kópiu hodnoty a aktualizuje ju s nižšou prioritou:

import { useDeferredValue, useMemo, memo } from "react";

// Pomalý komponent zabalený v memo
const HeavyChart = memo(function HeavyChart({ data }) {
  // Náročný render — tisíce SVG elementov
  return <svg>{/* ... */}</svg>;
});

function Dashboard({ data }) {
  // React odloží aktualizáciu deferredData
  const deferredData = useDeferredValue(data);
  const isStale = data !== deferredData;

  // useMemo zabráni zbytočnému prepočtu
  const processedData = useMemo(
    () => transformData(deferredData),
    [deferredData]
  );

  return (
    <div style={{ opacity: isStale ? 0.7 : 1 }}>
      <HeavyChart data={processedData} />
    </div>
  );
}

React Compiler: Automatická memoizácia v roku 2026

React Compiler (predtým známy ako React Forget) v roku 2026 automaticky spracúva memoizáciu komponentov. Manuálne použitie useMemo, useCallback a React.memo sa tak stáva legacy vzorom — kompilátor tieto optimalizácie vykoná za vás. Uistite sa, že váš build pipeline obsahuje React Compiler plugin. Podľa dostupných benchmarkov dokáže znížiť re-renderovú réžiu až o 40 %, čo je naozaj citeľný rozdiel.

Optimalizácia INP vo Vue a Angular

Vue 3 — v-memo a async komponenty

<!-- v-memo zabráni zbytočnému re-renderu ak sa závislosti nezmenili -->
<template>
  <div
    v-for="item in items"
    :key="item.id"
    v-memo="[item.id, item.updated]"
  >
    <ExpensiveComponent :data="item" />
  </div>
</template>

<script setup>
import { defineAsyncComponent } from "vue";

// Async komponent — načíta sa až keď je potrebný
const HeavyModal = defineAsyncComponent(() =>
  import("./HeavyModal.vue")
);
</script>

Angular — @defer a OnPush

<!-- Angular @defer — komponent sa načíta až pri interakcii -->
@defer (on interaction) {
  <heavy-data-table [data]="tableData" />
} @placeholder {
  <div class="skeleton-table">Načítavam tabuľku...</div>
}

<!-- OnPush change detection — Angular kontroluje komponent iba ak sa zmenia inputy -->
@Component({
  selector: "app-product-card",
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<div>{{ product.name }}</div>`,
})
export class ProductCardComponent {
  @Input() product!: Product;
}

Tretie strany: Skrytý zabijak INP

Skripty tretích strán — analytika, chatboty, reklamy, consent bannery — sú častou a bohužiaľ veľmi prehliadanou príčinou zlého INP. Priemerná stránka obsahuje viac ako 35 skriptov tretích strán a každý z nich môže pridať 100–500 ms blokovania hlavného vlákna. To je dosť šialené číslo, keď sa nad tým zamyslíte.

Audit a prioritizácia

Prvý krok je identifikácia. V Chrome DevTools na záložke Performance filtrujte podľa „Third-party" a zoraďte podľa blocking time. Typickí vinníci:

  • Google Tag Manager — samotný GTM je ľahký, ale kontajner plný tagov dokáže blokovať hlavné vlákno na sekundy. Auditujte každý tag a odstráňte nepoužívané.
  • Chat widgety (Intercom, Drift, Zendesk) — bežne pridávajú 200–800 ms blocking time. Nahraďte ich facade vzorom — zobrazíte statický obrázok alebo tlačidlo a skutočný widget načítate až po kliknutí.
  • Social embedy (YouTube, Twitter) — použite lite-youtube-embed alebo statické screenshoty s odkazom.
  • Reklamné skripty — načítavajte ich cez async atribút a nikdy nie v <head> synchronne.

Partytown: Skripty tretích strán vo Web Workeri

Knižnica Partytown presunie skripty tretích strán z hlavného vlákna do Web Workera. Hlavné vlákno zostáva voľné pre interakcie, zatiaľ čo analytika a tracking bežia na pozadí. V praxi to vyzerá takto:

<!-- Načítanie Partytown -->
<script src="/~partytown/partytown.js"></script>

<!-- Google Analytics beží vo Web Workeri namiesto hlavného vlákna -->
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script>
<script type="text/partytown">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag("js", new Date());
  gtag("config", "G-XXXXX");
</script>

Optimalizácia veľkosti DOM

Veľký DOM spomaľuje fázu Presentation Delay — prepočítanie štýlov, layout a paint jednoducho trvá dlhšie. Google odporúča menej ako 1 500 DOM uzlov, maximálnu hĺbku 32 úrovní a žiadny rodičovský element s viac ako 60 potomkami. V praxi tieto hranice prekonáva prekvapivo veľa webov.

Virtualizácia dlhých zoznamov

Ak zobrazujete stovky alebo tisíce položiek, virtualizácia je must-have. Renderuje iba viditeľné položky — namiesto 1 000 DOM uzlov máte v danom momente len 20–30:

// React príklad s react-window
import { FixedSizeList } from "react-window";

function ProductList({ products }) {
  const Row = ({ index, style }) => (
    <div style={style} className="product-row">
      {products[index].name} — {products[index].price} €
    </div>
  );

  return (
    <FixedSizeList
      height={600}
      width="100%"
      itemCount={products.length}
      itemSize={50}
    >
      {Row}
    </FixedSizeList>
  );
}

// Vanilla JS s content-visibility CSS
// Prehliadač preskočí renderovanie elementov mimo viewport
.product-card {
  content-visibility: auto;
  contain-intrinsic-size: 0 200px;
}

Okamžitá vizuálna spätná väzba

Niekedy jednoducho nemôžete interakciu urýchliť pod 200 ms — napríklad pri sieťovom požiadavku alebo komplexnom výpočte. V takom prípade je kľúčové poskytnúť okamžitú vizuálnu spätnú väzbu, aby používateľ vedel, že jeho vstup bol prijatý. Je to trochu psychologický trik, ale funguje výborne:

// Optimistická aktualizácia UI — zobrazí výsledok okamžite,
// server potvrdí neskôr
document.querySelector("#like-btn").addEventListener("click", async (e) => {
  const btn = e.currentTarget;
  const currentCount = parseInt(btn.dataset.count);

  // 1. Okamžitá vizuálna aktualizácia (pod 16 ms)
  btn.dataset.count = currentCount + 1;
  btn.textContent = `❤ ${currentCount + 1}`;
  btn.classList.add("liked");

  try {
    // 2. Sieťový požiadavok na pozadí
    await fetch("/api/like", { method: "POST", body: JSON.stringify({ id: btn.dataset.id }) });
  } catch {
    // 3. Rollback pri chybe
    btn.dataset.count = currentCount;
    btn.textContent = `❤ ${currentCount}`;
    btn.classList.remove("liked");
  }
});

Monitorovanie INP v produkcii

Jednorazová optimalizácia nestačí. INP sa môže zhoršiť pri každom nasadení nového kódu, aktualizácii skriptu tretej strany alebo zmene v profile zariadení vašich používateľov. Preto je proaktívny monitoring absolútne nevyhnutný.

Alerting na 80 % prahu

Nastavte alerty na 80 % Google prahu — teda INP nad 160 ms. To vám dá dostatočný čas reagovať predtým, ako sa zhoršenie premietne do 28-dňového okna CrUX dát a ovplyvní vaše pozície vo vyhľadávaní.

Sledovanie podľa zariadenia a stránky

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

onINP((metric) => {
  const payload = {
    value: metric.value,
    page: window.location.pathname,
    device: navigator.userAgent.includes("Mobile") ? "mobile" : "desktop",
    connection: navigator.connection?.effectiveType || "unknown",
    target: metric.attribution.interactionTarget,
    timestamp: Date.now(),
  };

  // Beacon API — spoľahlivé odoslanie aj pri zatvorení stránky
  navigator.sendBeacon("/api/vitals", JSON.stringify(payload));
});

Segmentujte dáta podľa zariadenia (mobil vs. desktop), typu pripojenia (4G vs. 3G), stránky a typu interakcie. Mobilné zariadenia majú typicky 3 až 5-krát pomalšie INP ako desktopy kvôli slabším procesorom — a práve tam je väčšina vášho trafficu.

Kontrolný zoznam optimalizácie INP

Na záver tu je stručný kontrolný zoznam, ktorý môžete použiť pri systematickej optimalizácii INP na vašom webe:

  1. Merajte — nasaďte web-vitals s attribution build a zbierajte reálne dáta od používateľov.
  2. Identifikujte — nájdite najpomalšie interakcie pomocou LoAF atribúcie.
  3. Rozdeľte úlohy — použite scheduler.yield() na rozdelenie úloh dlhších ako 50 ms.
  4. Presuňte prácu — CPU-náročné operácie presuňte do Web Workers.
  5. Auditujte tretie strany — odstráňte nepoužívané skripty, zvyšné načítavajte asynchrónne alebo cez Partytown.
  6. Zmenšite DOM — virtualizujte dlhé zoznamy, používajte content-visibility: auto.
  7. Optimalizujte frameworky — useTransition, useDeferredValue (React), v-memo (Vue), @defer (Angular).
  8. Vizuálna spätná väzba — pri pomalých operáciách zobrazujte spinnery a skeleton loadery okamžite.
  9. Monitorujte — nastavte alerty na INP > 160 ms a sledujte trendy po každom nasadení.

Často kladené otázky

Aký je rozdiel medzi INP a FID?

FID (First Input Delay) merala iba oneskorenie pred prvou interakciou na stránke a ignorovala čas spracovania aj vykreslenia. INP meria všetky tri fázy (input delay, processing time, presentation delay) a zachytáva všetky interakcie počas celého života stránky, nie len prvú. FID bola nahradená INP ako Core Web Vital v marci 2024, pretože jednoducho neposkytovala úplný obraz o tom, ako rýchlo stránka reaguje.

Ako zistím, ktorá interakcia spôsobuje zlé INP?

Najefektívnejší prístup je použiť attribution build knižnice web-vitals v kombinácii s Long Animation Frames (LoAF) API. Tieto nástroje presne identifikujú, ktorý element bol predmetom interakcie, ktorý skript spôsobil blokovanie a koľko času zabrala každá fáza. Pre lokálnu diagnostiku je zase najlepší Chrome DevTools Performance panel s nahrávkou konkrétnej interakcie.

Prečo mám dobré INP v lab testoch, ale zlé v teréne?

To je veľmi častá otázka. Lab testy prebiehajú na výkonných vývojárskych počítačoch s rýchlym pripojením. Vaši skutoční používatelia majú slabšie mobilné zariadenia, pomalšie pripojenia a bežia na nich rozšírenia prehliadača. Interakcie počas načítavania stránky majú 2,6-násobne vyššiu input delay. A navyše, skripty tretích strán sa v lab testoch často nenačítavajú rovnako ako v produkcii. Preto je Real User Monitoring (RUM) nevyhnutný.

Je scheduler.yield() podporovaný vo všetkých prehliadačoch?

V apríli 2026 je scheduler.yield() podporovaný v Chrome (od 2024) a Firefoxe (od augusta 2025). Safari ho zatiaľ nepodporuje. Pre plnú kompatibilitu používajte feature detection a fallback cez setTimeout(resolve, 0) alebo polyfill scheduler-polyfill. Fallback cez setTimeout funguje spoľahlivo, ale pokračovanie úlohy nemá prioritu a môže byť oneskorené inými čakajúcimi úlohami.

Koľko môže optimalizácia INP zlepšiť moje SEO pozície?

Podľa dát z roku 2026 weby s INP nad 200 ms strácajú priemerne 0,8 pozície v organickom vyhľadávaní a weby nad 500 ms strácajú 2 až 4 pozície na konkurenčných dotazoch. Weby, ktoré prejdú všetkými troma Core Web Vitals prahmi, vykazujú o 24 % nižšiu mieru odchodu a merateľne lepšie organické pozície. Zaujímavý príklad: Google uvádza, že RedBus zvýšil predaje o 7 % po optimalizácii INP — čo je pomerne presvedčivé číslo.

O Autorovi Editorial Team

Our team of expert writers and editors.