Largest Contentful Paint (LCP) to jedna z trzech kluczowych metryk Core Web Vitals, która mierzy czas ładowania największego widocznego elementu na stronie. Google wykorzystuje LCP jako czynnik rankingowy, a słaby wynik może negatywnie wpłynąć na pozycje w wynikach wyszukiwania.
Czym jest LCP?
LCP mierzy czas od rozpoczęcia ładowania strony do momentu wyrenderowania największego elementu w widocznym obszarze (viewport). Typowo tym elementem jest:
- Główny obraz (hero image)
- Duży blok tekstu
- Element
<video>z posterem - Element z obrazem tła (background-image)
Progi LCP
Google definiuje następujące progi:
| Wynik | Ocena |
|---|---|
| ≤ 2.5s | Dobry (zielony) |
| 2.5s - 4.0s | Wymaga poprawy (pomarańczowy) |
| > 4.0s | Słaby (czerwony) |
Jak zmierzyć LCP?
Narzędzia laboratoryjne (Lab data)
- Lighthouse (DevTools → Lighthouse)
- PageSpeed Insights - pagespeed.web.dev
- WebPageTest - webpagetest.org
- Chrome DevTools → Performance panel
Dane rzeczywiste (Field data)
- Google Search Console → Core Web Vitals
- Chrome UX Report (CrUX) - rzeczywiste dane od użytkowników Chrome
- web-vitals library - pomiary na własnej stronie
import { onLCP } from 'web-vitals';
onLCP(console.log);
// { name: 'LCP', value: 2547, rating: 'needs-improvement' }
Identyfikacja elementu LCP
W Chrome DevTools:
- Otwórz zakładkę Performance
- Naciśnij Ctrl+Shift+E (nagrywanie z przeładowaniem)
- Poszukaj znacznika LCP na timeline
- Kliknij, aby zobaczyć który element jest LCP
Główne przyczyny wolnego LCP
1. Wolny czas odpowiedzi serwera (TTFB)
Time to First Byte to czas od wysłania żądania do otrzymania pierwszego bajtu odpowiedzi. Jeśli TTFB jest wysoki, LCP automatycznie będzie opóźniony.
Rozwiązania:
- Użyj CDN (Cloudflare, Fastly, AWS CloudFront)
- Włącz kompresję Brotli/Gzip
- Zoptymalizuj zapytania do bazy danych
- Użyj cache’owania na serwerze (Redis, Memcached)
- Rozważ SSG zamiast SSR dla statycznych stron
2. Blokujące zasoby (render-blocking resources)
CSS i JavaScript w <head> blokują renderowanie strony.
Rozwiązania:
<!-- Zamiast -->
<link rel="stylesheet" href="styles.css">
<!-- Użyj inline critical CSS -->
<style>
/* Critical CSS dla above-the-fold */
.hero { ... }
</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<!-- JavaScript - użyj defer lub async -->
<script defer src="app.js"></script>
<script async src="analytics.js"></script>
3. Wolne ładowanie zasobów
Obrazy, fonty i inne zasoby muszą zostać pobrane zanim LCP zostanie wyrenderowany.
4. Client-side rendering
SPA (Single Page Applications) renderują treść po załadowaniu JavaScript, co opóźnia LCP.
Rozwiązania:
- Użyj SSR (Server-Side Rendering)
- Pre-rendering / SSG (Static Site Generation)
- Progressive Hydration
Optymalizacja obrazów - klucz do dobrego LCP
Obrazy to najczęstszy element LCP. Ich optymalizacja ma największy wpływ na wynik.
Format obrazów
| Format | Użycie | Kompresja |
|---|---|---|
| WebP | Uniwersalny, świetna kompresja | 25-35% mniejszy niż JPEG |
| AVIF | Najlepsza kompresja, ale wolniejsze dekodowanie | 50% mniejszy niż JPEG |
| JPEG | Fallback dla starszych przeglądarek | Baseline |
| PNG | Grafiki z przezroczystością | Bezstratny |
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero image" width="1200" height="600">
</picture>
Responsywne obrazy
Nie ładuj obrazu 4K na telefonie!
<img
src="hero-800.jpg"
srcset="
hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w,
hero-1600.jpg 1600w
"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
alt="Hero image"
width="1200"
height="600"
>
Lazy loading vs eager loading
Element LCP NIE powinien mieć loading="lazy"!
<!-- Hero image (LCP) - ładuj natychmiast -->
<img src="hero.jpg" alt="Hero" fetchpriority="high">
<!-- Obrazy poniżej fold - lazy load -->
<img src="product.jpg" alt="Product" loading="lazy">
Wymiary obrazów
Zawsze określaj width i height aby uniknąć layout shift:
<img src="hero.jpg" width="1200" height="600" alt="Hero">
Preload - przyspieszenie krytycznych zasobów
Preload informuje przeglądarkę, że zasób będzie potrzebny wkrótce i powinien być pobrany z wysokim priorytetem.
Preload dla obrazu LCP
<head>
<link rel="preload" as="image" href="hero.webp" type="image/webp">
<!-- Lub responsywnie -->
<link
rel="preload"
as="image"
href="hero-mobile.webp"
media="(max-width: 600px)"
>
<link
rel="preload"
as="image"
href="hero-desktop.webp"
media="(min-width: 601px)"
>
</head>
Preload dla fontów
Fonty często opóźniają renderowanie tekstu:
<link
rel="preload"
href="/fonts/inter.woff2"
as="font"
type="font/woff2"
crossorigin
>
Preconnect do zewnętrznych domen
Jeśli LCP image jest na CDN, nawiąż połączenie wcześniej:
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
Fetch Priority API
Nowoczesne przeglądarki wspierają fetchpriority do kontroli priorytetu zasobów:
<!-- Wysoki priorytet dla LCP image -->
<img src="hero.jpg" fetchpriority="high" alt="Hero">
<!-- Niski priorytet dla mniej ważnych obrazów -->
<img src="decoration.jpg" fetchpriority="low" alt="Decoration">
<!-- Wysoki priorytet dla krytycznego CSS -->
<link rel="stylesheet" href="critical.css" fetchpriority="high">
Optymalizacja CSS
Critical CSS inline
Wyodrębnij CSS potrzebny do renderowania above-the-fold i wstaw inline:
<head>
<style>
/* Critical CSS - tylko dla viewport */
header { ... }
.hero { ... }
nav { ... }
</style>
<!-- Reszta CSS asynchronicznie -->
<link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'">
</head>
Narzędzia do ekstrakcji Critical CSS:
- Critical (npm package)
- Critters (webpack plugin)
- PurgeCSS (usuwanie nieużywanego CSS)
Unikaj @import
/* Źle - tworzy łańcuch żądań */
@import url('fonts.css');
@import url('components.css');
/* Dobrze - używaj <link> w HTML */
Minifikacja i kompresja
# Minifikacja CSS
npx csso styles.css -o styles.min.css
# Kompresja Brotli
brotli -f styles.min.css
Optymalizacja JavaScript
Usunięcie render-blocking JS
<!-- Źle - blokuje renderowanie -->
<script src="app.js"></script>
<!-- Dobrze - defer dla głównego JS -->
<script defer src="app.js"></script>
<!-- Async dla niezależnych skryptów -->
<script async src="analytics.js"></script>
Code splitting
Nie ładuj całego bundla na każdej stronie:
// React - lazy loading komponentów
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
// Dynamiczny import
if (userClickedButton) {
const module = await import('./feature.js');
}
Tree shaking
Upewnij się, że bundler usuwa nieużywany kod:
// Importuj tylko to, co potrzebujesz
import { debounce } from 'lodash-es'; // Dobrze
import _ from 'lodash'; // Źle - importuje całą bibliotekę
Optymalizacja fontów
Font-display
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap; /* Pokaż fallback font, zamień gdy załadowany */
}
| Wartość | Zachowanie |
|---|---|
swap | Natychmiastowy fallback, zamiana po załadowaniu |
optional | Krótki fallback, może nie załadować fontu |
fallback | Krótki fallback (100ms), potem zamiana |
block | Niewidoczny tekst do załadowania (FOIT) |
Subsetting fontów
Ładuj tylko potrzebne znaki:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153; /* Tylko Latin */
}
Narzędzia:
- Glyphhanger - automatyczne subsetting
- Google Fonts - parametr
&text=lub&subset=
Self-hosting fontów
Hostowanie fontów na własnym serwerze eliminuje zewnętrzne żądania:
<!-- Zamiast Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter" rel="stylesheet">
<!-- Hostuj lokalnie -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
Optymalizacja serwera i CDN
Włącz HTTP/2 lub HTTP/3
HTTP/2 pozwala na równoległe ładowanie zasobów:
# nginx.conf
server {
listen 443 ssl http2;
# ...
}
Cache headers
# Długi cache dla statycznych zasobów
location ~* \.(js|css|png|jpg|webp|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Kompresja Brotli
# nginx.conf
brotli on;
brotli_comp_level 6;
brotli_types text/html text/css application/javascript image/svg+xml;
Edge caching (CDN)
Użyj CDN z edge lokalizacjami blisko użytkowników:
- Cloudflare
- Fastly
- AWS CloudFront
- Vercel Edge Network
Checklist optymalizacji LCP
Priorytet 1 - Najważniejsze
- Zidentyfikuj element LCP na stronie
- Preload dla obrazu/zasobu LCP
-
fetchpriority="high"dla elementu LCP - Usuń
loading="lazy"z elementu LCP - Optymalizuj obrazy (WebP/AVIF, kompresja)
Priorytet 2 - Ważne
- Critical CSS inline
- Defer/async dla JavaScript
- Preconnect do zewnętrznych domen
- Responsywne obrazy (srcset)
- font-display: swap dla fontów
Priorytet 3 - Dodatkowe
- HTTP/2 lub HTTP/3
- Kompresja Brotli
- CDN dla statycznych zasobów
- Self-hosting fontów
- Code splitting JavaScript
Podsumowanie
LCP to krytyczna metryka wydajności, która bezpośrednio wpływa na doświadczenie użytkownika i pozycje w Google. Kluczowe działania to:
- Zidentyfikuj element LCP - najczęściej hero image
- Preload krytycznych zasobów - obraz LCP, fonty
- Optymalizuj obrazy - format, rozmiar, responsywność
- Eliminuj blokujące zasoby - Critical CSS, defer JS
- Popraw TTFB - CDN, cache, optymalizacja serwera
Regularne monitorowanie LCP w Google Search Console i Lighthouse pomoże utrzymać dobre wyniki i reagować na problemy. Cel to poniżej 2.5 sekundy dla 75% użytkowników.
LCP to tylko jeden z elementów układanki - sprawdź kompletny przewodnik po technologiach web i ich wpływie na ranking Google, aby poznać pełny obraz optymalizacji technicznej.
Źródła
-
web.dev - Largest Contentful Paint (LCP) https://web.dev/articles/lcp
-
web.dev - Optimize LCP https://web.dev/articles/optimize-lcp
-
Google Search Central - Core Web Vitals https://developers.google.com/search/docs/appearance/core-web-vitals
-
Chrome Developers - Fetch Priority API https://developer.chrome.com/docs/lighthouse/performance/priority-hints
-
web.dev - Preload critical assets https://web.dev/articles/preload-critical-assets
-
MDN - Resource Hints https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload



