Obrazki, które zabijają Twoją stronę
Obrazy to zwykle największy ciężar strony. Pokazuję formaty, wymiary, kompresję, lazy-loading i responsywne srcset — z przykładami kodu i wagami w KB.
Jest jeden powód, dla którego strony ładują się wieczność, i prawie zawsze ten sam: obrazy. Nie skrypty, nie hosting, nie tajemnicza „magia” — po prostu zdjęcia wrzucone prosto z aparatu albo Canvy, ważące po kilka megabajtów każde. Dobra wiadomość jest taka, że to akurat najłatwiejszy do naprawienia element całej układanki. W tym wpisie pokażę dokładnie, gdzie tracisz wagę i jak ją odzyskać — z konkretnym kodem.
Dlaczego to właśnie obrazy
Otwórz dowolną stronę i sprawdź, co waży najwięcej. W zdecydowanej większości przypadków grafika to 50–70% całkowitej wagi. Jeden baner w nagłówku potrafi ważyć więcej niż cały kod HTML, CSS i JavaScript razem wzięty.
Problem polega na tym, że obraz nieoptymalny działa „cicho”. Strona wygląda dobrze, więc nikt nie podejrzewa, że pod spodem przeglądarka ściąga 8 MB zdjęć. A użytkownik na telefonie w terenie po prostu czeka — i często wychodzi. Jeśli chcesz zobaczyć, jak ta zwłoka przekłada się na utracone konwersje, opisałem to w dlaczego strona ładuje się 8 sekund.
Format ma znaczenie — i to ogromne
Ten sam obraz zapisany w różnych formatach potrafi ważyć dramatycznie różnie. Stare formaty (JPEG, PNG, GIF) były projektowane dekady temu. Nowe (WebP, AVIF) kompresują znacznie wydajniej przy tej samej jakości wizualnej.
Jak widać, przejście z PNG na AVIF potrafi obciąć wagę o 80–90% — przy obrazie, którego oko praktycznie nie odróżni. Oto ściąga, kiedy czego używać:
| Format | Kiedy używać | Uwagi |
|---|---|---|
| AVIF | Domyślny wybór na dziś | Najlepsza kompresja, wspierany przez wszystkie nowoczesne przeglądarki |
| WebP | Bezpieczny fallback | Trochę większy od AVIF, ale szerokie wsparcie od lat |
| JPEG | Fallback dla starych przeglądarek | Zdjęcia, gdy musisz mieć maksymalną zgodność |
| PNG | Grafiki z przezroczystością, logo, ikony | Ciężki dla zdjęć — nie używaj go do fotografii |
| GIF | Praktycznie nigdy | Animacje rób jako wideo (MP4/WebM) — waży wielokrotnie mniej |
| SVG | Logo, ikony, proste ilustracje | Wektor — skaluje się bez utraty jakości, mikroskopijna waga |
Najszybsza wygrana w całym wpisie
Jeśli masz na stronie animowane GIF-y, zamień je na wideo MP4/WebM. Animacja, która jako GIF waży 5 MB, jako wideo zmieści się często w 300 KB — przy tej samej, a nawet lepszej jakości.
Właściwe wymiary — nie serwuj 4000 px do kontenera 600 px
To najczęstszy i najboleśniejszy błąd. Wrzucasz zdjęcie prosto z aparatu — 4032 px szerokości, 6 MB — a na stronie wyświetla się ono w kontenerze o szerokości 600 px. Przeglądarka i tak pobiera cały plik, po czym zmniejsza go w locie. Marnujesz 90% pobranych danych.
Zasada jest prosta: obraz nie powinien być znacząco większy niż miejsce, w którym się wyświetla (z zapasem 2x na ekrany Retina). Jeśli kontener ma 600 px, serwuj 1200 px, a nie 4000 px.
Kompresja i narzędzia
Nawet po przeskalowaniu obraz zwykle da się jeszcze odchudzić bez widocznej różnicy. Trzy narzędzia, które polecam:
- Squoosh (
squoosh.app) — darmowy, w przeglądarce, z suwakiem porównującym jakość na żywo. Idealny do pojedynczych obrazów. - TinyPNG (
tinypng.com) — wrzucasz, dostajesz odchudzony plik. Świetny do szybkiej, masowej kompresji PNG/JPEG. - sharp — biblioteka do automatyzacji (Node.js). Gdy chcesz przerobić setki obrazów skryptem.
Przykład wsadowej konwersji do AVIF i WebP przez sharp:
import sharp from "sharp";
const sizes = [400, 800, 1200];
for (const width of sizes) {
await sharp("zdjecie.jpg")
.resize(width)
.avif({ quality: 55 })
.toFile(`zdjecie-${width}.avif`);
await sharp("zdjecie.jpg")
.resize(width)
.webp({ quality: 70 })
.toFile(`zdjecie-${width}.webp`);
}
Lazy-loading — ładuj dopiero to, co widać
Po co pobierać obrazek ze stopki strony, skoro użytkownik być może nigdy do niego nie doscrolluje? Lazy-loading odkłada pobieranie obrazów spoza widoku, aż użytkownik się do nich zbliży. W HTML to jeden atrybut:
<img src="zdjecie.jpg" alt="Opis" loading="lazy" width="1200" height="800">
Nie usypiaj obrazka z nagłówka
Obrazowi, który jest widoczny od razu (zwłaszcza temu „bohaterskiemu” z góry strony — Twojemu LCP), nie dawaj loading="lazy". Opóźnisz wtedy najważniejszy element i pogorszysz wynik. Lazy stosuj tylko poniżej pierwszego ekranu.
width i height — żeby strona nie skakała
Gdy <img> nie ma podanych wymiarów, przeglądarka nie wie, ile miejsca zarezerwować. Renderuje stronę, a po pobraniu obrazka cała treść nagle przeskakuje — to słynny CLS (skaczący układ). Lekarstwo: zawsze podawaj width i height (albo aspect-ratio w CSS). Przeglądarka rezerwuje miejsce z góry i nic nie skacze.
Responsywne obrazy — srcset i sizes
Telefon i monitor 4K nie potrzebują tego samego pliku. Po co wysyłać 1600 px na ekran o szerokości 400 px? Atrybuty srcset i sizes pozwalają przeglądarce samej wybrać najlepszy rozmiar dla danego urządzenia.
W kodzie wygląda to tak:
<img
src="zdjecie-800.jpg"
srcset="zdjecie-400.jpg 400w,
zdjecie-800.jpg 800w,
zdjecie-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 600px"
alt="Opis zdjecia"
loading="lazy"
width="1200"
height="800">
Mówiąc po ludzku: srcset to lista dostępnych rozmiarów, a sizes mówi przeglądarce, jak duży będzie obraz na ekranie. Telefon pobierze wersję 400 px, tablet 800 px, a desktop 1200 px — każdy dostaje dokładnie tyle, ile potrzebuje, i ani bajta więcej.
Jeśli chcesz jeszcze dorzucić różne formaty (AVIF z fallbackiem do JPEG), użyj <picture>:
<picture>
<source type="image/avif" srcset="zdjecie.avif">
<source type="image/webp" srcset="zdjecie.webp">
<img src="zdjecie.jpg" alt="Opis" loading="lazy" width="1200" height="800">
</picture>
CDN i Cloudflare Images
Ostatni element to dostarczanie obrazów blisko użytkownika. CDN trzyma kopie Twoich plików na serwerach rozsianych po świecie, więc nikt nie ściąga zdjęć z drugiego końca globu. Cloudflare (w darmowym planie) cache’uje statyczne obrazy automatycznie, a płatne Cloudflare Images potrafi przeskalować i przekonwertować obraz „w locie” pod konkretne urządzenie. O stawianiu Cloudflare przed stroną pisałem osobno: Cloudflare przed WordPressem za darmo.
Jak robi to Astro (i dlaczego warto)
Jeśli budujesz stronę na nowoczesnym frameworku, sporo z tego dostajesz za darmo. W Astro komponent <Image /> sam generuje wiele rozmiarów, konwertuje do AVIF/WebP, dodaje width/height i loading="lazy":
---
import { Image } from "astro:assets";
import zdjecie from "../assets/zdjecie.jpg";
---
<Image
src={zdjecie}
alt="Opis zdjecia"
widths={[400, 800, 1200]}
sizes="(max-width: 600px) 100vw, 600px"
/>
Z jednego pliku źródłowego Astro robi cały komplet zoptymalizowanych wariantów i wstawia poprawny srcset. To dokładnie ta robota, którą ręcznie opisałem wyżej — tylko zautomatyzowana podczas budowania strony.
Podsumowanie
Obrazy to najcięższa, a zarazem najłatwiejsza do naprawienia część strony. Zapamiętaj cztery kroki: przeskaluj do realnych wymiarów, przekonwertuj do AVIF/WebP, skompresuj i podaj wymiary plus loading="lazy" poniżej ekranu. Do tego srcset dla responsywności i CDN do dostarczania. To wszystko.
Jeśli przy okazji chcesz dobić do wysokiej oceny w testach, zerknij na Lighthouse 100/100 — czy warto i jak to ugryźć.
Masz stronę pełną ciężkich zdjęć i nie wiesz, od czego zacząć? Napisz do mnie — przejrzę grafikę i podpowiem, gdzie leży najwięcej zmarnowanych megabajtów.