Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Next.js Image Component - Optymalizacja zdjęć

Witaj @name! Czas stworzyć Treasure Gallery - piracką galerię zdjęć inspirowaną Instagramem. 📸

Zanim zaczniemy budować galerię, musisz nauczyć się jak Next.js obsługuje obrazy. Spoiler: znacznie lepiej niż zwykły

<img>
!

Problem ze zwykłym <img>

Tradycyjny tag

<img>
ma kilka problemów:

Brak automatycznej optymalizacji - duże pliki spowalniają stronę ❌ Brak lazy loading - wszystkie obrazy ładują się od razu ❌ Brak responsywności - jeden rozmiar dla wszystkich urządzeń ❌ Cumulative Layout Shift (CLS) - strona "skacze" gdy obrazy się ładują

Next.js Image Component - Rozwiązanie

Next.js ma wbudowany komponent

<Image>
który automatycznie:

Optymalizuje obrazy do formatu WebP/AVIF ✅ Lazy loading - ładuje tylko widoczne obrazy ✅ Responsive - dostarcza odpowiedni rozmiar dla urządzenia ✅ Zapobiega CLS - rezerwuje miejsce przed załadowaniem

Podstawowe użycie:

1import Image from 'next/image';
2
3export default function Gallery() {
4  return (
5    <Image
6      src="/treasure-map.jpg"
7      alt="Mapa skarbów"
8      width={800}
9      height={600}
10    />
11  );
12}

Ważne: Musisz podać

width
i
height
- Next.js potrzebuje ich do optymalizacji.

Obrazy z folderu public/

Pliki w folderze

public/
są dostępne bezpośrednio przez URL.

Struktura:

1public/
2├── images/
3│   ├── treasure-1.jpg
4│   ├── treasure-2.jpg
5│   └── pirate-ship.jpg
6└── logo.png

Użycie:

1<Image
2  src="/images/treasure-1.jpg"
3  alt="Złoty skarb"
4  width={600}
5  height={400}
6/>

Ścieżka zaczyna się od

/
- oznacza folder
public/
.

Zewnętrzne obrazy (z URL)

Możesz też ładować obrazy z zewnętrznych źródeł, ale musisz je skonfigurować.

1. Dodaj do next.config.js:

1// next.config.js
2module.exports = {
3  images: {
4    remotePatterns: [
5      {
6        protocol: 'https',
7        hostname: 'images.unsplash.com',
8      },
9      {
10        protocol: 'https',
11        hostname: 'i.imgur.com',
12      },
13    ],
14  },
15};

2. Użyj pełnego URL:

1<Image
2  src="https://images.unsplash.com/photo-1234567890"
3  alt="Piracki statek"
4  width={800}
5  height={600}
6/>

fill - Obrazy wypełniające kontener

Gdy nie znasz dokładnych wymiarów lub chcesz responsywny obrazek, użyj

fill
.

1<div className="relative w-full h-96">
2  <Image
3    src="/treasure-map.jpg"
4    alt="Mapa"
5    fill
6    className="object-cover"
7  />
8</div>

Ważne:

  • Rodzic musi mieć
    position: relative
  • Użyj
    object-cover
    lub
    object-contain
    dla kontroli skalowania

object-cover vs object-contain:

1// object-cover - obraz wypełnia kontener, może być przycinany
2<Image
3  src="/wide-image.jpg"
4  alt="Szeroki obraz"
5  fill
6  className="object-cover"
7/>
8
9// object-contain - cały obraz widoczny, może być pusty obszar
10<Image
11  src="/tall-image.jpg"
12  alt="Wysoki obraz"
13  fill
14  className="object-contain"
15/>

Priority - Wyłączenie lazy loading

Dla ważnych obrazów (powyżej fold - widocznych od razu), użyj

priority
:

1<Image
2  src="/hero-banner.jpg"
3  alt="Banner główny"
4  width={1200}
5  height={600}
6  priority
7/>

To mówi Next.js: "Załaduj ten obraz natychmiast, nie czekaj".

Placeholder - Efekt rozmycia podczas ładowania

Next.js może pokazać rozmyty placeholder podczas ładowania obrazu:

1<Image
2  src="/treasure.jpg"
3  alt="Skarb"
4  width={600}
5  height={400}
6  placeholder="blur"
7  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..." // Base64 tiny image
8/>

Lub automatycznie dla lokalnych obrazów:

1import treasureImage from '@/public/treasure.jpg';
2
3<Image
4  src={treasureImage}
5  alt="Skarb"
6  placeholder="blur"
7/>

Praktyczny przykład - Galeria Instagram

1import Image from 'next/image';
2
3interface GalleryPost {
4  id: number;
5  imageUrl: string;
6  caption: string;
7  author: string;
8  likes: number;
9}
10
11function GalleryGrid({ posts }: { posts: GalleryPost[] }) {
12  return (
13    <div className="grid grid-cols-3 gap-1">
14      {posts.map((post) => (
15        <div key={post.id} className="relative aspect-square group cursor-pointer">
16          <Image
17            src={post.imageUrl}
18            alt={post.caption}
19            fill
20            className="object-cover"
21          />
22
23          {/* Overlay przy hover */}
24          <div className="absolute inset-0 bg-black bg-opacity-50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
25            <div className="text-white text-center">
26              <p className="font-bold">❤️ {post.likes}</p>
27              <p className="text-sm">{post.caption}</p>
28            </div>
29          </div>
30        </div>
31      ))}
32    </div>
33  );
34}

Loading States - Skeleton UI

Pokaż placeholder ładowania, gdy obrazy się wczytują:

1'use client';
2
3import Image from 'next/image';
4import { useState } from 'react';
5
6export default function PhotoCard({ src, alt }: { src: string; alt: string }) {
7  const [isLoading, setIsLoading] = useState(true);
8
9  return (
10    <div className="relative aspect-square">
11      {isLoading && (
12        <div className="absolute inset-0 bg-gray-200 animate-pulse" />
13      )}
14
15      <Image
16        src={src}
17        alt={alt}
18        fill
19        className={`object-cover transition-opacity duration-300 ${
20          isLoading ? 'opacity-0' : 'opacity-100'
21        }`}
22        onLoad={() => setIsLoading(false)}
23      />
24    </div>
25  );
26}

Sizes - Responsywne rozmiary

Powiedz Next.js jakie rozmiary obrazu potrzebujesz dla różnych ekranów:

1<Image
2  src="/treasure.jpg"
3  alt="Skarb"
4  fill
5  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
6  className="object-cover"
7/>

Znaczenie:

  • Mobile (≤768px): 100% szerokości viewport
  • Tablet (≤1200px): 50% szerokości viewport
  • Desktop: 33% szerokości viewport

Quality - Kontrola jakości

Domyślnie Next.js kompresuje obrazy do quality=75. Możesz to zmienić:

1<Image
2  src="/high-quality-art.jpg"
3  alt="Dzieło sztuki"
4  width={1200}
5  height={800}
6  quality={90} // Wyższa jakość (większy plik)
7/>

Podsumowanie 🎓

Next.js Image - automatyczna optymalizacja ✅ width/height - wymagane dla lokalnych obrazów ✅ fill - responsive images w kontenerze ✅ priority - wyłącz lazy loading dla ważnych obrazów ✅ placeholder="blur" - efekt rozmycia podczas ładowania ✅ object-cover - obraz wypełnia kontener ✅ object-contain - cały obraz widoczny ✅ remotePatterns - konfiguracja zewnętrznych źródeł ✅ sizes - responsywne rozmiary dla optymalizacji

W następnym ćwiczeniu zbudujemy grid galerii z modalami! 📸

Do zobaczenia! 🚀

Przejdź do CodeWorlds