Core Web Vitals: jak zrychlit web a zlepšit LCP, INP a CLS
Co měří LCP, INP a CLS, jaké jsou hraniční hodnoty, jak je změřit na reálných uživatelích a konkrétní opravy, které mají největší efekt.
Core Web Vitals jsou tři metriky, kterými Google měří uživatelský zážitek z načítání a používání stránky. Ovlivňují hodnocení ve vyhledávání (jako jeden z mnoha signálů), ale hlavně odpovídají tomu, co lidé skutečně cítí: jak rychle uvidí obsah, jak rychle stránka reaguje a jestli jim pod prstem neuskakuje.
Tři metriky a jejich hranice
| Metrika | Co měří | Dobré | Špatné |
|---|---|---|---|
| LCP – Largest Contentful Paint | kdy se vykreslí největší prvek (hero obrázek, nadpis) | ≤ 2,5 s | > 4 s |
| INP – Interaction to Next Paint | jak rychle stránka vizuálně zareaguje na kliknutí či klávesu | ≤ 200 ms | > 500 ms |
| CLS – Cumulative Layout Shift | jak moc obsah neočekávaně poskakuje | ≤ 0,1 | > 0,25 |
Hodnotí se 75. percentil návštěv – aby web prošel, musí být metrika dobrá u alespoň tří čtvrtin uživatelů. INP v březnu 2024 nahradilo starší metriku FID.
Laboratorní vs. terénní data
- Lab data (Lighthouse, PageSpeed Insights – horní část): simulace na jednom zařízení. Skvělé na ladění, ale INP v nich změřit nejde (nikdo neklikne), Lighthouse místo něj ukazuje Total Blocking Time.
- Field data (Chrome UX Report v PageSpeed Insights, Search Console → Core Web Vitals): skutečná data uživatelů Chrome za posledních 28 dní. Rozhoduje to, co je tady.
Vlastní měření od reálných návštěvníků získáte knihovnou web-vitals:
import { onLCP, onINP, onCLS } from 'web-vitals';
function send(metric) {
navigator.sendBeacon('/analytics', JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
page: location.pathname,
}));
}
onLCP(send);
onINP(send);
onCLS(send);
sendBeacon odešle data i při zavírání stránky, kdy běžný fetch může být přerušen.
Zlepšení LCP
LCP prvek najdete v DevTools → Performance (nahrajte načtení stránky, v sekci Timings je značka LCP) nebo v reportu Lighthouse.
1. Hlavní obrázek načtěte co nejdřív.
<img src="hero.webp" alt="…" width="1200" height="600" fetchpriority="high">
Nikdy na něj nedávejte loading="lazy" – to je jedna z nejčastějších příčin špatného LCP. Pokud je obrázek v CSS jako background-image, prohlížeč ho objeví pozdě; pomůže preload:
<link rel="preload" as="image" href="hero.webp" fetchpriority="high">
2. Zmenšete obrázky. Formáty WebP a AVIF jsou výrazně menší než JPEG při podobné kvalitě. Používejte srcset, aby mobil nestahoval obrázek pro desktop.
3. Zrychlete odpověď serveru (TTFB). Cachování HTML, CDN, komprese (gzip/brotli), HTTP/2 nebo HTTP/3. Pokud server odpovídá 1,5 s, LCP pod 2,5 s jen těžko dáte.
4. Neblokujte vykreslení. Skripty v hlavičce označte defer, kritické CSS držte malé. Webové fonty načítejte s font-display: swap a hlavní font přednačtěte:
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
Zlepšení INP
INP zhoršují dlouhé úlohy na hlavním vlákně – cokoli nad 50 ms blokuje reakci na vstup.
1. Najděte viníka. DevTools → Performance → nahrajte záznam a klikněte na problematické tlačítko. Dlouhé úlohy jsou označené červeným rohem. Rozšíření Web Vitals nebo knihovna web-vitals/attribution ukáže, která interakce a který skript to byl.
2. Rozdělte práci a pusťte prohlížeč ke slovu.
button.addEventListener('click', async () => {
showSpinner(); // okamžitá vizuální odezva
// uvolnit hlavní vlákno, aby se spinner vykreslil
await new Promise(r => setTimeout(r, 0));
for (const chunk of chunks(items, 100)) {
process(chunk);
await new Promise(r => setTimeout(r, 0));
}
});
V Chromiu existuje i scheduler.yield(), který pokračuje s vyšší prioritou; v ostatních prohlížečích použijte setTimeout jako zálohu.
3. Omezte JavaScript. Méně kódu = méně parsování a spouštění. Rozdělte bundle (import() pro části, které nejsou potřeba hned), odstraňte nepoužívané knihovny a prověřte skripty třetích stran – chatovací widgety, analytiku a reklamy.
4. V Reactu zabraňte zbytečným rerenderům velkých stromů a dlouhé seznamy virtualizujte (např. TanStack Virtual). Pro méně naléhavé aktualizace je tu useTransition.
Zlepšení CLS
1. Rozměry u médií. Vždy width a height u <img>, <video> a <iframe>, nebo CSS aspect-ratio:
.video-embed { aspect-ratio: 16 / 9; width: 100%; }
2. Rezervujte místo pro dynamický obsah. Reklamy, cookie lišty, bannery a obsah načítaný přes API potřebují předem vymezený prostor (min-height). Cookie lištu dejte jako překryv (position: fixed), ne nad obsah.
3. Fonty. Výměna záložního fontu za webový může posunout text. Pomůže preload a deskriptory size-adjust, ascent-override v @font-face, které sladí rozměry záložního fontu.
4. Animace dělejte přes transform a opacity, ne přes top, height nebo margin – ty mění layout.
CLS prvky najdete v DevTools → Performance, v sekci Layout shifts.
Postup v praxi
- Otevřete PageSpeed Insights, podívejte se na field data a určete nejhorší metriku.
- Najděte konkrétní prvek nebo interakci (Lighthouse, Performance panel).
- Opravte jednu věc, nasaďte, změřte.
- Sledujte Search Console – terénní data se aktualizují s 28denním oknem, zlepšení se projeví postupně.
Optimalizujte primárně mobil se střední třídou výkonu – tam jsou problémy nejvýraznější a tam je většina návštěv.