Largest Contentful Paint je nemilosrdný. Prah 2.5 sekundy je pre 75. percentil reálnych návštevníkov — nie pre tvoj test cez fiber zo stoličky. Za posledných šesť mesiacov som spravil cez 30 LCP auditov, väčšinu na WordPresse a WooCommerce, časť na Astro/Next.js. Vzorce sa opakujú. Tu je sedem najčastejších, v poradí frekvencie, s identifikáciou aj fixom.
1. Hero image bez fetchpriority alebo preloadu
Kráľ kategórie. Browser vidí <img> v HTML, ale objaví ho až keď preparsuje pol stránky CSS a JS. Medzitým fetch-uje tucet skriptov a fontov.
Identifikácia: WebPageTest waterfall — hero obrázok sa začne sťahovať až po domContentLoaded. Connection View ukáže, že hero soup-uje rovnakú connection s analytics scriptmi.
Fix: dva atribúty.
<img src="/hero.webp"
fetchpriority="high"
loading="eager"
decoding="async"
width="1200" height="600"
alt="...">
A pre istotu <link rel="preload" as="image" href="/hero.webp" fetchpriority="high"> v <head>. Typicky úspora 0.6–1.2 s LCP. Bližšie na web.dev/articles/fetch-priority.
2. Render-blocking JS pred body close
Google Maps embed, YouTube facade, Tidio chat. Plugin shoves <script> tag tesne pred </body> bez async ani defer. Hlavné vlákno sa zastaví na 200–600ms, LCP element nemá kedy paint-núť.
Identifikácia: Lighthouse “Eliminate render-blocking resources” + waterfall riadok bez async/defer flagu.
Fix: defer ak script potrebuje DOM, async inak. Alebo ešte lepšie — zlož do facade pattern. Pre YouTube: lite-youtube-embed — namiesto 540KB iframe naloaduje 3KB custom element ktorý sa zmení na iframe až po kliku.
<lite-youtube videoid="dQw4w9WgXcQ"></lite-youtube>
3. Slow TTFB (>800ms) z lacného hostingu
Čistá fyzika: ak server odpovedá 1.2s, LCP nikdy nebude pod 2.5s. Najčastejšie u zdieľaných hostingov za €3/mesiac s WP bez page cache. Postgres/MySQL behajú na rovnakej VPSke s ďalšími 800 doménami, I/O wait je groteskný.
Identifikácia: WebPageTest “First Byte” číslo. Ak >800ms na production zo SK, máš problém. Pozri aj cez curl -w "@curl-format.txt" z viacerých lokácií.
Fix v poradí ROI:
- Page cache plugin (WP Rocket, LiteSpeed Cache, FastCGI cache na nginx). TTFB klesne z 1.2s na 80ms cez noc.
- Object cache (Redis) — pre WooCommerce kategórie s 50+ produktmi rozdiel 200ms+.
- Lepší hosting — €8–15/mes (kvalitný shared) vs €25 (managed cloud). Detailne v Hostingy v SK z pohľadu výkonu.
4. WebP/AVIF chýba, kompresia 90%+
Hero obrázok 1.4MB JPEG pri kvalite 95. WebP s kvalitou 80 by mal cca 180KB pri vizuálne identickom výsledku.
Identifikácia: waterfall — najväčší súbor je obrázok >300KB.
Fix: server-side konverzia v image_make_intermediate_size filter (WP), alebo Cloudflare Polish, alebo build-time cez sharp. Pre Astro stačí <Image> z astro:assets — auto WebP/AVIF s srcset.
// Astro
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
<Image src={hero} alt="..." widths={[400, 800, 1200]} formats={['avif', 'webp']} />
Reálne čísla z auditu: hero 1.4MB JPEG → 142KB AVIF. LCP -0.8s.
5. Custom font bez font-display: swap
Hero element je často <h1> s custom fontom. Bez font-display: swap browser čaká až 3 sekundy na font, potom rendruje text. LCP ide spať.
Identifikácia: filmstrip — text sa objaví až sekundu po obrázku. Lighthouse hlási “Ensure text remains visible during webfont load”.
Fix:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2-variations');
font-display: swap;
font-weight: 100 900;
}
A <link rel="preload" as="font" type="font/woff2" href="/fonts/inter-var.woff2" crossorigin> v <head>. Pri kritickom fonte na hero. Bonus: jeden variable font namiesto 4–6 statických — úspora 400KB.
6. Cumulative blocking time z reklám a widgetov
Mediavine, Google AdSense, sponsored embedy. Ad slot zavolá googletag.cmd.push() ktorý spustí 8 ďalších skriptov. Každý z nich blokuje main thread po 50–150ms. Hero medzi tým paint-uje.
Identifikácia: DevTools Performance → záznam first 5s → “Long Tasks” z domén googletagservices, doubleclick, mediavine.
Fix: ad slot nikdy nesmie byť above-the-fold ak chceš dobré LCP. Reálne kompromis: prvá reklama až po hero (typicky po prvých 600px). Pre lazy ad SDK pozri @aditude/ad-sdk alebo native Mediavine “lazy ad” mode.
7. Hero ako React/Vue island ktorý hydratuje
Modern stack syndrom. Hero je <HeroComponent /> v Next.js, server vyrenderuje statický HTML, ale označí ho ako client component. LCP sa technicky zameria na hydrated DOM, čo prichádza až po stiahnutí 200KB JS bundle.
Identifikácia: Chrome DevTools → Performance → kliknú LCP marker → “Related Node”. Ak je to element vnútri React boundary s "use client" direktívou, máš problém.
Fix: označ hero ako server component. V Astro: bez client:* direktívy. V Next.js: vyhneš sa "use client" v hero komponente; interakcie zabuduj do menšieho child komponentu.
// Hero.tsx — server component, žiadny "use client"
export default function Hero() {
return (
<section>
<h1>Headline</h1>
<Image src="/hero.webp" priority alt="..." />
<CTAButton /> {/* "use client" tu, nie vyššie */}
</section>
);
}
Postup pri reálnom audite
- WebPageTest s 4G mobile profilom z Frankfurtu (pre SK) alebo Prahy. Filmstrip + Waterfall + Connection View.
- CrUX dashboard alebo PageSpeed Insights — reálne dáta z Chrome users, nie laboratórne.
- Chrome DevTools Performance — záznam pre identifikáciu konkrétneho LCP elementu (kliknú “LCP” v timeline).
- Identifikuj jednu z týchto sedmich príčin a fixni. Otestuj. Ďalšia.
Najlepší LCP fix je často kombinácia 2–3 z týchto: hero fetchpriority + WebP + page cache. To spravidla stačí na presun z “Poor” do “Good” za pár hodín práce.