PORADNIKI · INSPIRACJE · NARZĘDZIA · DLA PROJEKTANTÓWMagazyn kreatywny
design/blog.MAGAZYN KREATYWNY
Start / Grafika rastrowa / Artykuł
Grafika rastrowa

Jak zoptymalizować obrazy na stronę WWW bez spowalniania ładowania

Autor: •
Napis HTTP ułożony z klawiszy klawiatury na różowym tle
Rate this post

Obrazy często są największymi plikami pobieranymi przez stronę, dlatego mogą wyraźnie spowolnić jej ładowanie — zwłaszcza na telefonach. Problem zwykle nie wynika z samego zdjęcia, lecz z wysłania do przeglądarki zbyt dużego wariantu, niewłaściwego formatu albo pliku bez dopasowania do miejsca, w którym ma się wyświetlić. Aby tego uniknąć, trzeba kolejno dobrać format, wymiary, kompresję i sposób serwowania obrazu.

Pytania, które zwykle pojawiają się przed publikacją, są proste: jaki format wybrać, do jakiego rozmiaru przyciąć piksele, ile skompresować, czy wystarczy jeden plik, oraz czy leniwe ładowanie nie zepsuje największego elementu na ekranie. Poniższe wskazówki odpowiadają na nie w kolejności, w jakiej realnie przygotowuje się bitmapę do WWW.

Dlaczego optymalizacja grafiki rastrowej to podstawa szybkiego ładowania witryny

Nieprzetworzone piksele wchodzą w trzy koszty naraz: transfer, dekodowanie i miejsce w pamięci. Wskaźnik Largest Contentful Paint (LCP) mierzy moment, w którym największy widoczny element — często zdjęcie hero — jest namalowany. Jeśli ten plik waży 1,8 MB, LCP czeka na sieć niezależnie od tego, jak szybki jest sam HTML.

Wektor (SVG, ikona z CSS) przeglądarka rysuje z opisu kształtów. Bitmapę musi rozpakować piksel po pikselu. Na słabszym telefonie dekodowanie JPEG o szerokości 4000 px potrafi zająć więcej czasu niż sam download przy dobrym Wi-Fi. Dlatego „plik się ściągnął” nie oznacza jeszcze „obraz jest gotowy”.

Typowy błąd to wgranie zdjęcia prosto z aparatu albo z banku zdjęć. Aparat zapisuje 12–24 MP, przestrzeń barw aparatu i miniaturę podglądu. Bank często dokłada duży PNG „na wszelki wypadek”. Strona nie potrzebuje ani jednej z tych warstw, dopóki slot na layout nie ma kilku tysięcy pikseli.

Co sprawdzić: w narzędziach deweloperskich, zakładka Network, filtr Img. Zsumuj transfer obrazów przy pierwszym wejściu na podstronę. Jeśli same grafiki przekraczają kilkaset kilobajtów na widok mobilny, reszta optymalizacji frontu nie nadrobi tego opóźnienia.

Wskazówka 1: Wybierz nowoczesny format pliku dopasowany do rodzaju grafiki

Porównanie formatów JPEG, PNG, WebP oraz AVIF

Format nie jest kwestią mody. Decyduje o tym, czy przeglądarka dostanie zdjęcie z płynnymi przejściami tonalnymi, czy grafikę z ostrymi krawędziami i przezroczystością.

FormatNajlepsze zastosowaniePrzezroczystośćUwaga praktyczna
JPEGFotografie, tła, produkty bez alfaNieDobry fallback; słabszy stosunek wagi do jakości niż WebP/AVIF
PNGLogo, ikony rastrowe, zrzuty UI, ostre krawędzieTakNa zdjęciach zwykle za ciężki
WebPZdjęcia i grafiki z alfą, szeroka kompatybilnośćTakDomyślny wybór dla większości stron
AVIFDuże zdjęcia, gdzie liczy się każdy kilobajtTakMniejszy plik, czasem wolniejsze kodowanie i dekodowanie

Krok 1: Rozpoznaj zawartość bitmapy

Zdjęcie produktu z miękkim światłem i cieniami trzymaj w formacie stratnym (WebP albo AVIF, z JPEG jako zapas). Logo z płaskimi kolorami i przezroczystym tłem zostaw w PNG albo w WebP bezstratnym — kompresja JPEG rozmyje krawędzie i doda obwódki. Zrzut interfejsu z drobnym tekstem też źle znosi mocną kompresję stratną: literki zaczynają „pływać”. [1]

Krok 2: Konwertuj do formatu nowej generacji

Dla szerokiej zgodności eksportuj WebP. AVIF dokładaj tam, gdzie plik jest duży i często oglądany: baner, galeria, zdjęcie kategorii. Nie zamieniaj wszystkiego hurtowo jednym suwakiem. Ten sam poziom jakości przy AVIF daje zwykle mniejszy plik niż przy JPEG, więc „jakość 80” w dwóch formatach nie oznacza tej samej utraty detalu.

Krok 3: Zostaw fallback dla starszych przeglądarek

Znacznik picture pozwala podać AVIF, potem WebP, a na końcu JPEG albo PNG. Przeglądarka bierze pierwszy obsługiwany typ. Samo podmienienie rozszerzenia w src bez wariantu zapasowego zostawia część użytkowników z pustym miejscem albo z błędem typu pliku.

<picture>
  <source type="image/avif" srcset="sofa-800.avif 800w, sofa-1600.avif 1600w" sizes="(max-width: 700px) 100vw, 720px">
  <source type="image/webp" srcset="sofa-800.webp 800w, sofa-1600.webp 1600w" sizes="(max-width: 700px) 100vw, 720px">
  <img src="sofa-800.jpg" alt="Szara sofa narożna w salonie" width="800" height="533">
</picture>

Pułapka: zapisanie fotografii w bezstratnym PNG „żeby nie tracić jakości”. Przy zdjęciu sofy różnica wagi bywa kilkukrotna, a oko i tak nie zobaczy korzyści na ekranie sRGB.

Co sprawdzić: w Network typ MIME ma być image/webp albo image/avif, nie application/octet-stream. Zły nagłówek Content-Type potrafi zablokować wyświetlenie mimo poprawnego pliku.

Wskazówka 2: Dopasuj fizyczne wymiary w pikselach przed eksportem z programu

Krok 1: Odczytaj szerokość slotu, nie szerokość monitora

Kontener CSS mówi, ile pikseli CSS zajmuje obraz. Kolumna bloga 720 px, karta produktu 320 px, hero na pełną szerokość viewportu. To nie to samo co rozdzielczość laptopa 1920 px. Zmierz slot w inspektorze na desktopie i na szerokości około 360–400 px.

Krok 2: Skaluj rastrowo przed wrzuceniem na serwer

Ekrany o zagęszczeniu 2x potrzebują około dwukrotności pikseli CSS, żeby krawędzie nie były miękkie. Miniatura 300 px CSS uzasadnia plik około 600 px szerokości, nie 4000 px. Hero 720 px CSS na desktopie zwykle wystarcza przy 1440 px. Powyżej 2x zysk ostrości maleje, a waga rośnie niemal z kwadratem wymiaru: podwojenie szerokości i wysokości to około cztery razy więcej pikseli.

Krok 3: Wyostrz po zmniejszeniu

Skalowanie w dół rozmywa krawędzie. Lekkie wyostrzenie po eksporcie (mały promień, umiarkowana ilość) przywraca czytelność detalu bez aureoli. Najpierw zmniejsz, potem wyostrz, na końcu kompresuj. Odwrotna kolejność utrwala szum, który kompresja i tak musi zapisać.

Typowy błąd: plik 4000 px wstawiony do miniatury 300 px i „zmniejszony” wyłącznie stylem width: 100%. Przeglądarka pobiera i dekoduje pełną bitmapę. CSS zmienia tylko sposób rysowania, nie liczbę pikseli w pliku.

Co sprawdzić: w inspekcji elementu porównaj rendered size z intrinsic size. Jeśli intrinsic jest wielokrotnie większy od wyrenderowanego, plik jest za duży względem slotu.

Wskazówka 3: Zastosuj kontrolowaną kompresję i usuń zbędne metadane

Granica między kompresją bezstratną a stratną

Bezstratna kompresja porządkuje dane bez wyrzucania pikseli. Przy zdjęciach daje skromny zysk. Stratna usuwa informacje, których oko słabo rozróżnia — i tu jest większość oszczędności. Granica nie leży w magicznej liczbie, tylko w podglądzie w skali 100% na docelowym tle strony, nie na szachownicy edytora.

Krok 1: Ustal jakość, nie „maksymalną ostrość”

Dla fotografii start w okolicach 75–85% jakości JPEG/WebP jest zwykle bezpiecznym punktem: detal skóry, tkaniny i krawędzi produktu zostaje, a waga spada mocno względem jakości 95–100. Tekst na grafice, cienkie linie i logo wymagają wyższej jakości albo formatu bezstratnego. Ciemne gradienty (niebo, tło studia) szybciej pokazują pasy — tam obniżaj jakość ostrożniej albo zostaw nieco większy plik. [5]

Krok 2: Zredukuj profil do sRGB i usuń EXIF

Przeglądarki na WWW oczekują sRGB. Szeroki profil z aparatu bywa ignorowany albo interpretowany inaczej, a i tak zajmuje miejsce. Usuń dane EXIF: model aparatu, GPS, miniaturę podglądu, historię edycji. To nie poprawia ostrości, ale obcina kilkadziesiąt–kilkaset kilobajtów i nie wystawia lokalizacji sesji zdjęciowej.

Krok 3: Kompresuj raz, właściwym koderem

MozJPEG (albo równoważny koder JPEG), eksport WebP z sensownym ustawieniem jakości oraz OxiPNG / podobne narzędzia dla PNG dają lepszy wynik niż „Zapisz dla Internetu” sprzed dekady. Narzędzia online są wygodne przy pojedynczych plikach. Przy katalogu setek zdjęć sensowniej spiąć ten sam koder w eksporcie z programu albo w potoku publikacji, żeby jakość nie skakała między produktami.

Pułapka: podwójna kompresja. Najpierw mocny JPEG z aparatu albo z banku, potem jeszcze raz „optymalizator” na tym samym pliku. Bloki 8×8 stają się widoczne, a drugi przebieg niewiele już zbiera. Kompresuj z wersji roboczej o wysokiej jakości, nie z pliku już mocno zniszczonego.

Co sprawdzić: zdjęcie na pełną szerokość treści, po WebP albo AVIF, najczęściej mieści się w okolicy 100–150 KB, jeśli slot nie jest panoramicznym hero. Hero może być cięższy, ale jeśli regularnie przekracza 200–300 KB, wymiary albo jakość są ustawione zbyt wysoko.

Wskazówka 4: Wdróż responsywne serwowanie grafik za pomocą atrybutów srcset i sizes

Jeden „złoty” plik 1600 px jest za duży na kartę w siatce i za mały na hero 2x. Zestaw szerokości pozwala przeglądarce wybrać plik pod slot i gęstość ekranu, zamiast zgadywać.

Płytki Scrabble układające słowo Website na drewnianej powierzchni
Źródło: Pexels | Autor: Markus Winkler

Krok 1: Wygeneruj kilka szerokości, nie dziesięć losowych

Dla większości layoutów wystarczą warianty w okolicach 400, 800, 1200 i 1600 px. Miniatury mogą kończyć się na 800 px. Hero może potrzebować 2000 px tylko wtedy, gdy slot naprawdę jest tak szeroki przy 2x. Każdy dodatkowy wariant to miejsce na dysku i czas generowania — nie zastępuje decyzji o maksymalnym rozmiarze.

Krok 2: Opisz pliki deskryptorem szerokości

W srcset dopisuj 400w, 800w, nie procenty jakości. Deskryptor w mówi, ile pikseli ma plik. Przeglądarka sama przeliczy to względem gęstości ekranu. Atrybut src zostaw jako sensowny fallback — zwykle wariant średni, nie największy.

Krok 3: Powiedz przeglądarce, ile miejsca zajmie slot

Sam srcset z deskryptorami w nie wystarcza. Bez sizes przeglądarka zakłada, że obraz zajmie całą szerokość viewportu, i przy gęstości 2x ściąga niemal dwukrotność szerokości okna — nawet gdy karta w siatce ma 320 px CSS. Atrybut sizes opisuje właśnie ten slot, nie plik.

Wartość to lista warunków i szerokości. Pierwszy pasujący warunek wygrywa. Na końcu zostaw szerokość domyślną, bez media query — to rozmiar na desktopie, gdy żaden wcześniejszy warunek nie pasuje.

<img
  src="sofa-800.jpg"
  srcset="sofa-400.jpg 400w, sofa-800.jpg 800w, sofa-1200.jpg 1200w, sofa-1600.jpg 1600w"
  sizes="(max-width: 700px) 100vw, 720px"
  width="800"
  height="533"
  alt="Szara sofa narożna w salonie">

Ten zapis mówi: poniżej 700 px obraz jest pełną szerokością okna, powyżej — kolumną 720 px. Na telefonie 390 px CSS i ekranie 2x przeglądarka szuka pliku około 780 px i bierze wariant 800w. Na desktopie przy slocie 720 px i 2x celuje w okolice 1440 px, więc wybiera 1600w, a nie „największy, jaki jest”. Gdybyś zostawił domyślne 100vw, ten sam desktop 1440 px CSS przy 2x mógłby pójść po plik bliższy 2880 px — którego w zestawie nie ma, więc i tak poleci największy, już bez sensu dopasowany do kolumny.

Szerokość w sizes licz w pikselach CSS slotu, nie w pikselach pliku. Dla karty produktu w siatce trzech kolumn sensowny zapis to na przykład (max-width: 600px) 100vw, (max-width: 1000px) 50vw, 320px. Jednostka vw jest tu udziałem viewportu, nie „jakością”. Jeśli layout ma stały margines albo sidebar, odjąć go w warunku — 100vw na wąskiej kolumnie obok menu zawyża wybór o kilkaset pikseli.

Ten sam sizes powtórz przy każdym source w picture. Przeglądarka najpierw wybiera format, potem wariant szerokości. Różne sizes na AVIF i na JPEG dają niespójny plik w zależności od przeglądarki.

Pułapka: skopiowany sizes="100vw" przy każdej miniaturze w galerii. Na retina desktop każda karta prosi o hero, a siatka dwunastu zdjęć mnoży ten błąd. Drugi częsty błąd to warunek, który nigdy nie pasuje do CSS — na przykład 50vw przy obrazie, który w rzeczywistości jest pełną szerokością kontenera max-width: 720px.

Co sprawdzić: w Network, po wyczyszczeniu cache, porównaj żądany plik na szerokości około 390 px i na desktopie. Miniatura nie powinna brać wariantu 1600w. W inspektorze atrybut currentSrc pokazuje, który plik wygrał. Jeśli na wąskim slocie zawsze wygrywa największy, sizes jest za szeroki albo go nie ma.

Wskazówka 5: Skonfiguruj natywny lazy loading i zablokuj opóźnienie obrazu LCP

Leniwe ładowanie ma sens dla grafik poniżej pierwszego ekranu. Obraz, od którego zależy LCP — zwykle hero albo duże zdjęcie produktu nad zgięciem — musi startować od razu. Ten sam atrybut na obu typach grafik psuje albo transfer, albo metrykę.

Krok 1: Oznacz tylko to, czego nie widać na starcie

Natywny mechanizm to loading="lazy" na img. Przeglądarka odracza pobieranie, dopóki element nie zbliży się do viewportu. Działa bez biblioteki i bez obserwatora przecięcia. Karty w dalszej części listy, zrzuty w artykule i zdjęcia w stopce są dobrymi kandydatami.

<img
  src="karta-400.jpg"
  srcset="karta-400.jpg 400w, karta-800.jpg 800w"
  sizes="(max-width: 600px) 100vw, 320px"
  width="400"
  height="300"
  loading="lazy"
  decoding="async"
  alt="Fotel boucle, widok z przodu">

decoding="async" pozwala dekodować bitmapę poza głównym wątkiem, gdy przeglądarka może to zrobić bez blokowania rysowania. Nie zastępuje właściwego rozmiaru pliku. Przy dziesiątkach miniatur i tak ogranicz liczbę obrazów w pierwszym HTML — leniwe ładowanie nie usuwa ich z dokumentu, tylko przesuwa transfer.

Krok 2: Hero i LCP zostaw poza lazy

Nie dawaj loading="lazy" obrazowi, który jest największym elementem widocznym od razu. Przeglądarka czeka z żądaniem, LCP rośnie o setki milisekund, a użytkownik widzi pusty slot. Dla tego jednego pliku ustaw loading="eager" albo w ogóle pomiń atrybut — domyślnie obraz ładuje się zachłannie — i podnieś priorytet:

<img
  src="sofa-800.jpg"
  srcset="sofa-800.jpg 800w, sofa-1200.jpg 1200w, sofa-1600.jpg 1600w"
  sizes="(max-width: 700px) 100vw, 720px"
  width="800"
  height="533"
  fetchpriority="high"
  alt="Szara sofa narożna w salonie">

fetchpriority="high" dotyczy wyłącznie kandydata na LCP, nie każdej grafiki „na wszelki wypadek”. Kilka obrazów z wysokim priorytetem konkuruje ze sobą i z CSS. Jeden hero, reszta bez tego atrybutu.

Jeśli hero jest w picture, atrybuty loading, fetchpriority, width, height i alt siedzą na img, nie na source. width i height rezerwują proporcję slotu, zanim plik dojdzie — inaczej treść pod obrazem skacze i LCP liczy się od późniejszego przesunięcia.

Krok 3: Nie chowaj LCP za skryptem

Wtyczki, które podmieniają src na placeholder i dociągają prawdziwy plik dopiero po JavaScript, obchodzą natywny priorytet. Hero wtedy startuje po parsowaniu i wykonaniu skryptu, często po innych zasobach. Dla obrazu nad zgięciem trzymaj prawdziwy adres w HTML od pierwszej odpowiedzi serwera. Placeholdery i biblioteki lazy zostaw dla galerii poniżej foldu, jeśli natywny atrybut z jakiegoś powodu nie wystarcza.

Drugie opóźnienie robi preload ustawiony na zły wariant. <link rel="preload" as="image"> ma sens tylko wtedy, gdy wskazuje dokładnie ten plik, który wygra srcset i sizes dla typowego pierwszego widoku — zwykle mobilnego. Preload największego 1600w przy slocie 390 px ściąga zbędne piksele równolegle z właściwym, mniejszym plikiem. Jeśli nie możesz zsynchronizować preloadu z sizes, lepiej go nie dodawać i zdać się na fetchpriority="high" na img.

Co sprawdzić: w Network, przy czystym wejściu na szerokości telefonu, hero ma start żądania blisko początku waterfallu, a miniatury poniżej foldu nie startują w tej samej fali. W panelu Performance kandydat LCP to ten obraz, a nie późniejszy element po doskoku layoutu. Jeśli LCP czeka na obraz z loading="lazy", zdejmij ten atrybut z pierwszego ekranu. [3]

Lista kontrolna przed publikacją

Zanim plik trafi na produkcję, sprawdź go na prawdziwym slocie, nie w podglądzie eksportu. Poniższe punkty łapią błędy, które zostają po poprawnym eksporcie i poprawnym HTML.

  • Format i fallback. Hero i zdjęcia produktowe idą jako AVIF albo WebP, ze starszym JPEG lub PNG tylko w picture. Ikona, która jest kształtem, nie powinna być bitmapą.
  • Wariant, który naprawdę leci. Po czystym wejściu na około 390 px CSS miniatura nie bierze pliku 1600w. W inspektorze currentSrc ma pasować do slotu razy gęstość, nie do największego pliku w katalogu.
  • Ten sam sizes przy każdym source. Warunek opisuje szerokość CSS kontenera, z odjętym sidebarem i marginesem. Skopiowane 100vw przy karcie w siatce jest błędem, nie skrótem.
  • Jeden priorytet. Obraz LCP nie ma loading="lazy", ma prawdziwy adres w pierwszym HTML i co najwyżej jeden fetchpriority="high". Reszta grafik poniżej pierwszego ekranu może być leniwa. [2]
  • Proporcja slotu. width i height siedzą na img. Po wyłączeniu cache treść pod hero nie może doskoczyć, gdy plik dojdzie.
  • Preload albo nic. link rel="preload" wskazuj tylko na wariant, który wygra typowy pierwszy widok. Preload 1600w przy slocie telefonu dociąga zbędne piksele obok właściwego pliku — wtedy lepiej preloadu nie dodawać.
  • Waga po fakcie. Zdjęcie na szerokość kolumny treści, już w nowoczesnym formacie, zwykle zostaje w okolicy 100–150 KB. Hero może być cięższy; regularnie powyżej 200–300 KB znaczy, że slot albo jakość są ustawione zbyt wysoko.

Jeśli któryś punkt pada, popraw atrybut albo wariant szerokości, zanim ruszysz jakość kodera. Drugi przebieg kompresji na już wysłanym pliku rzadko ratuje metrykę, a prawie zawsze widać go na krawędziach.

Najczęściej zadawane pytania (FAQ)

Jaki format obrazu wybrać na stronę WWW?

Zdjęcia najlepiej eksportować do WebP albo AVIF, z JPEG jako formatem zapasowym. PNG sprawdzi się przy logo, zrzutach interfejsu i grafikach wymagających przezroczystości.

Jak dobrać rozmiar obrazu w pikselach?

Rozmiar należy dopasować do szerokości slotu w układzie strony oraz gęstości ekranu. Dla obrazu o szerokości 300 px CSS zwykle wystarczy plik około 600 px na ekranie 2x.

Czy można zmniejszyć duży obraz wyłącznie za pomocą CSS?

Nie. CSS zmienia sposób wyświetlania, ale przeglądarka nadal pobiera i dekoduje pełną bitmapę. Obraz trzeba zmniejszyć przed umieszczeniem go na serwerze.

Czy warto usuwać dane EXIF z obrazów?

Tak. Usunięcie EXIF może zmniejszyć rozmiar pliku i ograniczyć ujawnianie informacji, takich jak model aparatu, lokalizacja GPS czy miniatura podglądu.

Po co stosować srcset i sizes?

Atrybuty srcset i sizes pozwalają przeglądarce wybrać wariant obrazu odpowiedni do szerokości slotu oraz gęstości ekranu. Dzięki temu telefon nie musi pobierać zbyt dużego pliku. [4]

Szybka kontrola obrazu przed publikacją

Największy zysk daje nie agresywna kompresja jednego pliku, lecz właściwy wariant dostarczony właściwemu urządzeniu. Zacznij od obrazu LCP i zdjęć widocznych na pierwszym ekranie, potem sprawdź w narzędziach deweloperskich, co faktycznie trafia do przeglądarki. Jeśli plik pasuje do slotu, ma nowoczesny format i nie blokuje kluczowego widoku, obrazy przestają być hamulcem ładowania strony.

  • Wymiary: plik ma odpowiadać szerokości slotu w układzie, a nie maksymalnej rozdzielczości zdjęcia źródłowego.
  • Format: dla zdjęć wybierz AVIF lub WebP, a JPEG traktuj jako fallback; PNG zostaw dla grafiki wymagającej przezroczystości lub ostrych krawędzi.
  • Responsywność: użyj srcset i sizes, aby telefon nie pobierał wariantu przeznaczonego dla szerokiego ekranu.
  • Priorytet: obraz LCP powinien być dostępny w początkowym HTML i nie może mieć loading="lazy".
  • Stabilność układu: dodaj atrybuty width i height, aby strona nie przeskakiwała podczas ładowania grafiki.

Źródła

Podobał Ci się artykuł? Odkryj więcej publikacji w naszych kategoriach.