Dlaczego obrazy wpływają na LCP, CLS i Core Web Vitals?
W przypadku obrazu LCP liczy się nie tylko rozmiar pliku. Przeglądarka musi wcześnie odkryć właściwy URL, nadać mu odpowiedni priorytet, pobrać zasób i wyrenderować go po zastosowaniu CSS. Obraz w HTML może zostać znaleziony przez preload scanner wcześniej niż tło zapisane w zewnętrznym CSS. Z kolei błędny sizes może sprawić, że poprawnie odkryty obraz nadal będzie niepotrzebnie ciężki.
CLS jest osobnym problemem. width i height nie określają renderowanego rozmiaru, ale przekazują przeglądarce proporcje potrzebne do zarezerwowania miejsca. Dla fill tę odpowiedzialność przejmuje stabilny kontener. Next.js automatyzuje te elementy, lecz nadal wymaga poprawnej informacji o layoucie.
next/image w Next.js: co robi pod maską?
next/image to wrapper nad tagiem <img>, który automatycznie:
Konwertuje format: domyślnie serwuje WebP, a AVIF po dodaniu go do
images.formats.Skaluje rozmiar: generuje warianty dla różnych viewportów.
Lazy loading: ładuje obrazy dopiero, gdy są blisko viewportu.
Zapobiega CLS: wymaga podania
widthiheightalbo użyciafillw kontenerze o stałym formacie.Blur placeholder: wyświetla rozmyty podgląd podczas ładowania, ale dla zdalnych obrazów zwykle wymaga własnego
blurDataURL.
Podstawowe użycie next/image
Prop sizes w next/image: podstawa prawidłowego skalowania
sizes informuje przeglądarkę, jaką szerokość będzie miał obraz na różnych viewportach. W next/image wpływa również na zestaw szerokości wygenerowanych w srcset. Bez tej informacji responsywny obraz może zostać potraktowany jak 100vw i pobrać wariant większy niż potrzebny.
Prop fill w next/image: obrazy responsywne bez wymiarów
Gdy nie znasz wymiarów (np. zdjęcia z CMS), użyj fill z kontenerem o określonym aspect ratio:
Konfiguracja domen zewnętrznych dla next/image
Aby next/image mógł optymalizować obrazy z zewnętrznych źródeł, musisz dodać je do konfiguracji, ale nie rób szerokiego wildcarda na całą domenę, jeśli obrazy leżą tylko w jednym katalogu.
W Next.js 16 domyślna allowlista jakości to [75]. Rozszerz ją tylko wtedy, gdy komponenty rzeczywiście przekazują inne quality. minimumCacheTTL jest dolną granicą: końcowy czas cache jest większą wartością z tej konfiguracji i nagłówka Cache-Control źródła. Next.js nie udostępnia prostego API do unieważniania cache, więc dla często zmienianych obrazów stosuj wersjonowany URL zamiast bardzo długiego TTL.
remotePatterns traktuj jak regułę bezpieczeństwa. Ogranicz protokół, host, ścieżkę i parametry zapytania. search: '' blokuje query string, a pominięcie search dopuszcza dowolne parametry i może zwiększyć liczbę wariantów cache. Domyślny optimizer nie przekazuje nagłówków uwierzytelniających do zdalnego źródła; prywatne obrazy wymagają podpisanego publicznego URL-a, własnego endpointu albo świadomego użycia unoptimized.
Cache, koszty i limity Image Optimization w Next.js
next/image optymalizuje obrazy na żądanie, co jest wygodne, ale ma konsekwencje, o których warto pamiętać:
pierwsze wejście na nowy wariant może być wolniejsze, ponieważ serwer generuje obraz
każdy rozmiar, format i quality to osobny wariant do cache
szerokie
sizesi przypadkowequalitypotrafią pomnożyć liczbę wariantówna platformach serverless lub managed hosting liczba optymalizacji może mieć koszt
przy bardzo dużej bibliotece zdjęć dedykowany image CDN bywa tańszy i stabilniejszy
Dlatego w projektach e-commerce i marketplace nie wystarczy użyć masowo next/image. Potencjalną liczbę wpisów w cache wyznaczają źródła, żądane szerokości, formaty oraz jakości, ale warianty powstają dopiero po konkretnych żądaniach. Sprawdź realny ruch i rachunki hostingu zamiast zakładać, że każdy teoretyczny wariant zostanie wygenerowany.
AVIF zwykle zmniejsza transfer względem WebP, ale pierwsze kodowanie trwa dłużej, a każdy format zajmuje osobny cache. Next.js nadal rekomenduje WebP dla większości zastosowań. Jeśli włączasz kilka formatów i stawiasz proxy lub CDN przed własnym serwerem Next.js, warstwa pośrednia musi przekazywać nagłówek Accept.
Bezpieczne źródła obrazów w Next.js
Nie używaj hostname: '**' ani nie pomijaj wszystkich pozostałych ograniczeń. Taka konfiguracja pozwala osobom trzecim wykorzystywać Twój Image Optimization API do pobierania i przetwarzania niezamierzonych URL-i. Dla lokalnych źródeł możesz analogicznie zastosować localPatterns.
Natywny <img> z srcset: kiedy wystarczy zamiast next/image?
Nie każdy projekt potrzebuje next/image. Jeśli masz statyczną stronę, kontrolujesz warianty obrazów i nie potrzebujesz automatycznej konwersji formatów, natywny HTML jest prostszy i daje pełną kontrolę.
Kiedy wybrać natywny srcset
- Static export (
output: 'export'): wbudowany optimizer wymaga serwera; w eksporcie użyj zewnętrznego loadera,unoptimizedalbo własnego<picture>. - Pełna kontrola nad wariantami: sam generujesz dokładne rozmiary przez skrypt.
- Art direction: na mobile chcesz inny kadr niż na desktopie.
- Minimalizm: nie chcesz dodatkowej warstwy abstrakcji.
srcset odpowiada za wybór rozmiaru tego samego obrazu, a <picture> pozwala wybrać format albo inny kadr. W przykładzie hero nie ma loading="lazy", ponieważ opóźniałoby to kandydata LCP. JPEG również ma responsywny srcset, więc fallback nie oznacza automatycznie pobrania jednego dużego pliku.
Tego nie zastąpisz samym sizes, ponieważ sizes nie zmienia kadru. getImageProps() zachowuje optymalizację i generowanie srcset przez Next.js, a <picture> odpowiada za art direction. Nie dodawaj tutaj preload, jeśli różne viewporty mają różnych kandydatów LCP; loading="eager" i fetchPriority="high" trafią do elementu <img> przez fallback.
CDN do obrazów: Cloudinary, Imgix i Cloudflare Images
Dedykowane do obrazów oferują transformacje w locie: skalowanie, kadrowanie, filtry, konwersję formatów bez generowania wariantów w build time.
Integracja CDN z next/image przez custom loader
Po tej konfiguracji każde użycie next/image korzysta z Cloudinary, a sizes nadal steruje wygenerowanym srcset. Globalny loader ma sens tylko wtedy, gdy wszystkie przekazywane źródła należą do tego samego modelu URL. W aplikacji mieszającej lokalne importy i Cloudinary zastosuj loader tylko w dedykowanym komponencie albo rozdziel sposób renderowania obu grup.
CDN jest dobrym rozwiązaniem, jeśli źródło obrazów jest zmienne lub już należy do CMS-a oferującego transformacje. Skala biblioteki jest ważna, ale nie stanowi jedynego kryterium: nawet mały serwis na Sanity może skorzystać z istniejącego image CDN, a duży katalog z kilkoma stałymi wariantami może działać bez osobnej usługi.
Przy CMS-ach masz trzy rozsądne warianty:
| Źródło | Najlepszy wybór | Dlaczego |
|---|---|---|
| lokalne grafiki marketingowe | statyczny import + next/image | automatyczne wymiary i blur, mało wariantów |
| CMS z własnym image CDN, np. Sanity | loader albo natywne URL-e CDN | CMS już umie transformować obrazy |
| e-commerce z tysiącami zdjęć | dedykowany image CDN | koszty, cache i transformacje są poza serwerem Next.js |
| static export | <picture> / srcset albo CDN loader | brak serwera optymalizującego |
Nie dubluj optymalizacji, bo jeśli Cloudinary albo Sanity już zwraca f_auto, q_auto i właściwą szerokość, przepuszczanie tego jeszcze przez domyślny optimizer Next.js nie ma sensu. W takiej architekturze użyj custom loadera albo natywnych URL-i CDN.
next/image vs srcset vs CDN: porównanie podejść
| Kryterium | next/image z domyślnym loaderem | Natywny srcset | Image CDN z loaderem |
|---|---|---|---|
| Konwersja formatu | według images.formats | w pipeline builda | według możliwości dostawcy |
| Responsywne szerokości | generowany srcset | warianty przygotowane ręcznie | transformacje URL i generowany srcset |
| Lazy loading | domyślnie włączone | przez loading="lazy" | zależy od użytego elementu lub komponentu |
| Rezerwacja miejsca | wymagane wymiary albo fill | ręczne wymiary lub CSS | zależy od integracji w HTML |
| Blur placeholder | automatyczny dla obsługiwanych importów | własny LQIP | zależy od dostawcy |
| Koszt | CPU, cache lub opłata hostingu | build, storage i transfer | usługa, transformacje i transfer |
| Static export | loader albo unoptimized | działa | działa przez URL-e lub loader |
| Kontrola | wysoka w ramach API Next.js | pełna | wysoka w ramach API dostawcy |
Jak wybrać optymalizację obrazów w Next.js?
Najprostszy sposób podjęcia decyzji:
- Masz standardową aplikację Next.js z serwerem albo Vercel? Zacznij od
next/image. - Robisz
output: 'export'bez zewnętrznego loadera? Wybierz<picture>isrcset. - CMS już oferuje transformacje albo potrzebujesz ich na żądanie? Użyj jego image CDN lub loadera.
- Potrzebujesz różnych kadrów na mobile i desktopie? Użyj
<picture>, nawet jeśli reszta obrazów idzie przeznext/image. - Masz jeden hero i kilka grafik marketingowych? Statyczne importy +
next/imagesą najprostsze i zwykle wystarczają. - Masz już zoptymalizowane URL-e z Sanity, Cloudinary albo Imgix? Nie optymalizuj ich drugi raz bez powodu.
Najlepsze praktyki optymalizacji obrazów
Obraz LCP: preload, loading="eager" albo fetchPriority="high"
W Next.js 16 prop preload zastąpił przestarzały priority. Użyj go, gdy obraz jest jednoznacznym kandydatem na i powinien zostać odkryty już w <head>. Nie oznaczaj w ten sposób całego rzędu kart, ponieważ preload wymusza pobranie zasobu i może konkurować z CSS, fontami oraz właściwym LCP.
Nie łącz preload z loading ani fetchPriority. Gdy kandydat zależy od viewportu albo obraz jest wcześnie widoczny i łatwo odkrywalny w HTML, częściej wystarczy loading="eager" lub fetchPriority="high". Preload odpowiada za wczesne odkrycie, a Fetch Priority jest wskazówką dotyczącą ważności pobierania; to nie są synonimy.
Poprawny alt dla SEO i dostępności
Pierwszy tekst jest zbyt ogólny, drugi może być poprawny, jeśli kolor i model są istotną informacją niewystępującą obok. Nie duplikuj w alt podpisu, nazwy produktu ani tekstu linku tylko po to, żeby dodać słowa kluczowe.
Unikaj layout shift przez aspect ratio
Przy width i height przeglądarka zna proporcje przed pobraniem pliku. Przy fill rodzic musi mieć stabilny rozmiar oraz pozycjonowanie, na przykład klasy relative aspect-video pokazane wcześniej. Samo position: relative bez wysokości albo aspect-ratio nie rezerwuje miejsca.
Mierz realny wpływ obrazów na wydajność
Po zmianie obrazów sprawdź:
- Czy LCP wskazuje właściwy element w PageSpeed Insights lub WebPageTest?
- Czy zasób LCP został odkryty wcześnie i nie ma
loading="lazy"? - Czy pobrany rozmiar obrazu odpowiada layoutowi, a nie pełnej szerokości ekranu?
- Czy serwer zwrócił oczekiwany
Content-Type,Cache-Controli rozmiar transferu? - Czy CLS jest zerowy dzięki
width/height,fillz aspect ratio albo stabilnemu kontenerowi?
W DevTools otwórz Network, włącz kolumny Resource Size, Priority i Content-Type, a potem porównaj mobile i desktop z wyłączonym cache. W konsoli sprawdź img.currentSrc, img.naturalWidth i img.clientWidth. Jeśli karta o szerokości 280 px regularnie pobiera obraz 1200 px, sprawdź sizes, gęstość ekranu i dostępne szerokości w srcset.
Panel Performance pokaże, czy problemem jest późne odkrycie URL-a, długie pobieranie, czy renderowanie po zakończeniu requestu. Test laboratoryjny powtórz na ograniczonym CPU i sieci, a decyzje produkcyjne potwierdź danymi terenowymi z Core Web Vitals.


