Komponent Image i optymalizacja obrazów w Next.js 16
Kurs Next.js · Moduł 3: Stylowanie i optymalizacja wizualna
W Metropolis Quantum, wizualna komunikacja odgrywa kluczową rolę. Futurystyczne hologramy, cyfrowe billboardy i immersyjne wyświetlacze są wszechobecne w krajobrazie miasta. Jednak, podobnie jak w przypadku rzeczywistych miast, inżynierowie muszą dbać o wydajność systemów wyświetlania, aby obrazy ładowały się szybko i nie zużywały zbyt wiele zasobów.
W świecie aplikacji webowych, obrazy stanowią jedną z największych przeszkód w osiąganiu optymalnej wydajności stron. Duże, nieskompresowane zdjęcia mogą znacząco spowolnić ładowanie strony i pogorszyć doświadczenie użytkownika. Na szczęście, Next.js 16 oferuje potężne narzędzie do optymalizacji obrazów - komponent Image.
Dlaczego optymalizacja obrazów jest ważna?
Zanim zagłębimy się w szczegóły komponentu Image, warto zrozumieć, dlaczego optymalizacja obrazów jest tak istotna:
- Wydajność strony - obrazy stanowią często ponad 50% wagi strony internetowej
- Core Web Vitals - metryki takie jak LCP (Largest Contentful Paint) są bezpośrednio związane z czasem ładowania obrazów
- SEO - szybsze strony są lepiej pozycjonowane w wynikach wyszukiwania
- Doświadczenie użytkownika - nikt nie lubi czekać na załadowanie się zawartości
- Zużycie danych - dla użytkowników mobilnych, duże obrazy mogą szybko zużyć limit danych
- Dostępność - odpowiednio zoptymalizowane obrazy są bardziej dostępne dla osób z wolniejszym połączeniem internetowym
Tradycyjne podejście do obrazów w HTML
W tradycyjnym HTML, obrazy są zazwyczaj dodawane za pomocą tagu <img>:
1<img src="/images/quantum-city.jpg" alt="Panorama Metropolis Quantum" />To proste podejście ma jednak kilka wad:
- Brak automatycznej optymalizacji - obrazy są serwowane w oryginalnym formacie i rozmiarze
- Brak responsywności - obrazy nie dostosowują się automatycznie do różnych rozmiarów ekranu
- Brak leniwego ładowania - wszystkie obrazy są ładowane od razu, niezależnie od ich widoczności
- Brak priorytetyzacji - nie można łatwo określić, które obrazy są krytyczne dla wyświetlenia strony
Komponent Image w Next.js 16
Komponent Image z Next.js rozwiązuje te problemy i oferuje szereg dodatkowych korzyści:
- Automatyczna optymalizacja - konwersja do nowoczesnych formatów (WebP, AVIF)
- Dostosowanie rozmiaru - serwowanie obrazów w odpowiednim rozmiarze dla urządzenia
- Leniwe ładowanie - obrazy są ładowane tylko wtedy, gdy zbliżają się do viewport
- Unikanie przesunięć układu - rezerwacja przestrzeni dla obrazów przed ich załadowaniem
- Wsparcie dla wielu źródeł - łatwe określenie różnych obrazów dla różnych rozdzielczości
- Optymalizacja pod kątem Core Web Vitals - poprawa metryk takich jak LCP i CLS
Podstawowe użycie komponentu Image
Aby zacząć korzystać z komponentu Image, najpierw należy go zaimportować z next/image:
1import Image from 'next/image';
2
3export default function QuantumCityView() {
4 return (
5 <div className="city-view">
6 <h1>Panorama Metropolis Quantum</h1>
7 <Image
8 src="/images/quantum-city.jpg"
9 alt="Panorama Metropolis Quantum z lotu ptaka"
10 width={1200}
11 height={600}
12 />
13 </div>
14 );
15}W powyższym przykładzie, komponent Image wymaga kilku atrybutów:
src- ścieżka do obrazualt- alternatywny tekst dla dostępnościwidthiheight- szerokość i wysokość obrazu w pikselach
Statyczne importy obrazów
Next.js pozwala również na statyczne importowanie obrazów, co daje dodatkowe korzyści, takie jak automatyczne określanie wymiarów:
1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5 return (
6 <div className="city-view">
7 <h1>Panorama Metropolis Quantum</h1>
8 <Image
9 src={quantumCityImage}
10 alt="Panorama Metropolis Quantum z lotu ptaka"
11 // width i height są automatycznie określane z metadanych obrazu
12 />
13 </div>
14 );
15}Responsywne obrazy
Komponent Image można łatwo dostosować do różnych rozmiarów ekranu za pomocą stylów CSS:
1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5 return (
6 <div className="city-view">
7 <h1>Panorama Metropolis Quantum</h1>
8 <div className="relative w-full h-[50vh]">
9 <Image
10 src={quantumCityImage}
11 alt="Panorama Metropolis Quantum z lotu ptaka"
12 fill
13 style={{ objectFit: 'cover' }}
14 />
15 </div>
16 </div>
17 );
18}W tym przykładzie:
- Atrybut
fillpowoduje, że obraz wypełnia kontener rodzica - Style
objectFit: 'cover'zapewnia, że obraz zachowuje proporcje, przycinając go w razie potrzeby - Kontener rodzica musi mieć pozycję
relativelubabsolute
Priorytetyzacja obrazów
Dla obrazów, które są widoczne "above the fold" (czyli w górnej części strony bez przewijania), warto użyć atrybutu preload. W Next.js 16 zastąpił on przestarzały atrybut priority, który wciąż działa, ale nie należy go już używać w nowym kodzie:
1<Image
2 src="/images/hero-quantum-city.jpg"
3 alt="Panorama Metropolis Quantum"
4 width={1200}
5 height={600}
6 preload
7/>Atrybut preload powoduje, że:
- Next.js wstawia do
<head>znacznik<link rel="preload">dla tego obrazu - Przeglądarka zaczyna pobierać obraz, zanim dotrze do niego w treści strony
- Obraz jest dostępny jak najszybciej, co poprawia LCP
Dokumentacja Next.js 16 radzi używać preload tylko dla jednego obrazu LCP, np. zdjęcia hero. W pozostałych przypadkach wystarczy loading="eager" albo fetchPriority="high".
Obsługa obrazów z CMS lub zewnętrznych źródeł
Aby używać obrazów z zewnętrznych źródeł (np. CMS, CDN, API), trzeba wskazać Next.js dozwolone serwery w pliku next.config.js. Starsze projekty robią to opcją domains:
1// next.config.js
2module.exports = {
3 images: {
4 domains: ['cdn.quantum-city.com', 'images.cms-provider.com'],
5 },
6}Ta opcja jest przestarzała od Next.js 14, dlatego w Next.js 16 używaj "remotePatterns", które dają bardziej precyzyjną kontrolę:
1// next.config.js
2module.exports = {
3 images: {
4 remotePatterns: [
5 {
6 protocol: 'https',
7 hostname: 'cdn.quantum-city.com',
8 port: '',
9 pathname: '/images/**',
10 },
11 {
12 protocol: 'https',
13 hostname: '**.cms-provider.com',
14 port: '',
15 pathname: '/assets/**',
16 },
17 ],
18 },
19}Placeholders i efekt rozmazania
Next.js 16 oferuje kilka sposóbów na poprawę doświadczenia użytkownika podczas ładowania obrazów:
Placeholder z efektem blur
1<Image
2 src="/images/quantum-city.jpg"
3 alt="Panorama Metropolis Quantum"
4 width={1200}
5 height={600}
6 placeholder="blur"
7 blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1200' height='600'%3E%3Crect width='100%25' height='100%25' fill='%23071731'/%3E%3C/svg%3E"
8/>W tym przykładzie:
placeholder="blur"włącza efekt rozmazania podczas ładowania obrazublurDataURLokreśla kolor tła używany podczas ładowania obrazu (zakodowany jako URL base64)
Automatyczny efekt rozmazania dla statycznych importów
Kiedy używasz statycznego importu obrazu, Next.js automatycznie generuje wersję rozmazaną:
1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5 return (
6 <Image
7 src={quantumCityImage}
8 alt="Panorama Metropolis Quantum"
9 placeholder="blur"
10 // blurDataURL jest generowany automatycznie
11 />
12 );
13}Animacje ładowania obrazów
Możesz dodać animacje ładowania obrazu za pomocą CSS:
1import Image from 'next/image';
2import styles from './image.module.css';
3
4export default function QuantumCityView() {
5 return (
6 <Image
7 src="/images/quantum-city.jpg"
8 alt="Panorama Metropolis Quantum"
9 width={1200}
10 height={600}
11 className={styles.imageTransition}
12 />
13 );
14}1/* image.module.css */
2.imageTransition {
3 opacity: 0;
4 transition: opacity 0.5s ease-in-out;
5}
6
7.imageTransition:global(.loaded) {
8 opacity: 1;
9}Zaawansowane funkcje komponentu Image
Adaptatywne obrazy i art direction
W przypadku, gdy chcesz wyświetlać różne obrazy dla różnych rozmiarów ekranu, możesz użyć atrybutu srcSet:
1<div className="relative aspect-video w-full">
2 <picture>
3 <source
4 media="(max-width: 640px)"
5 srcSet="/images/quantum-city-mobile.jpg"
6 />
7 <source
8 media="(max-width: 1024px)"
9 srcSet="/images/quantum-city-tablet.jpg"
10 />
11 <source
12 media="(min-width: 1025px)"
13 srcSet="/images/quantum-city-desktop.jpg"
14 />
15 <Image
16 src="/images/quantum-city-desktop.jpg"
17 alt="Panorama Metropolis Quantum"
18 fill
19 style={{ objectFit: 'cover' }}
20 />
21 </picture>
22</div>Obsługa obrazów w różnych formatach
Choć Next.js automatycznie konwertuje obrazy do WebP, możesz również użyć tagu <picture> do obsługi różnych formatów:
1<picture>
2 <source srcSet="/images/quantum-city.avif" type="image/avif" />
3 <source srcSet="/images/quantum-city.webp" type="image/webp" />
4 <Image
5 src="/images/quantum-city.jpg"
6 alt="Panorama Metropolis Quantum"
7 width={1200}
8 height={600}
9 />
10</picture>Obsługa obrazów z transparentnością
Dla obrazów z transparentnością (PNG, SVG), warto rozważyć wyłączenie konwersji do WebP:
1<Image
2 src="/images/quantum-logo.png"
3 alt="Logo Metropolis Quantum"
4 width={200}
5 height={200}
6 style={{ objectFit: 'contain' }}
7 unoptimized
8/>Atrybut unoptimized wyłącza optymalizację Next.js dla danego obrazu, co może być przydatne dla:
- Obrazów z transparentnością
- Już zoptymalizowanych obrazów
- Animowanych GIF-ów
Konfigurowanie optymalizacji obrazów w Next.js 16
Next.js oferuje wiele opcji konfiguracyjnych dla optymalizacji obrazów w pliku next.config.js:
1// next.config.js
2module.exports = {
3 images: {
4 // Przestarzałe od Next.js 14 - zamiast domains używaj remotePatterns
5 domains: ['cdn.quantum-city.com'],
6
7 // Bardziej szczegółowa konfiguracja dla zewnętrznych obrazów
8 remotePatterns: [
9 {
10 protocol: 'https',
11 hostname: '**.cms-provider.com',
12 port: '',
13 pathname: '/assets/**',
14 },
15 ],
16
17 // Obsługiwane formaty
18 formats: ['image/webp', 'image/avif'],
19
20 // Dozwolone wartości quality (od Next.js 16 domyślnie tylko [75])
21 qualities: [50, 75, 90],
22
23 // Konfiguracja cache (od Next.js 16 domyślnie 14400 s, czyli 4 godziny)
24 minimumCacheTTL: 60, // w sekundach
25
26 // Limit rozmiarów obrazów
27 deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
28 imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // od Next.js 16 wartości 16 nie ma w domyślnej liście
29
30 // Własny loader dla obrazów (np. Cloudinary, imgix)
31 loader: 'default',
32
33 // Ścieżka do endpointu optymalizacji obrazów
34 path: '/_next/image',
35
36 // Wyłączenie automatycznej optymalizacji dla wszystkich obrazów
37 unoptimized: false,
38 },
39}Next.js 16 zmienił kilka wartości domyślnych: minimumCacheTTL wynosi teraz 4 godziny (wcześniej 60 sekund), z imageSizes zniknęła szerokość 16 pikseli, a qualities pozwala domyślnie tylko na jakość 75. Doszły też opcje bezpieczeństwa: maximumRedirects (domyślnie najwyżej 3 przekierowania) i dangerouslyAllowLocalIP, bez której Next.js nie optymalizuje obrazów z adresów lokalnych.
Użycie loaderów zewnętrznych dostawców
Next.js obsługuje również popularne serwisy optymalizacji obrazów:
1// next.config.js
2module.exports = {
3 images: {
4 loader: 'cloudinary',
5 loaderFile: './my/image/loader.js',
6 // Domena Cloudinary
7 domains: ['res.cloudinary.com'],
8 },
9}Możesz również stworzyć własny loader:
1// my/image/loader.js
2export default function myImageLoader({ src, width, quality }) {
3 return `https://cdn.quantum-city.com/images/${src}?w=${width}&q=${quality || 75}`
4}I użyć go w komponencie Image:
1import Image from 'next/image';
2import myLoader from '@/my/image/loader';
3
4export default function QuantumCityView() {
5 return (
6 <Image
7 loader={myLoader}
8 src="quantum-city.jpg"
9 alt="Panorama Metropolis Quantum"
10 width={1200}
11 height={600}
12 />
13 );
14}Przykłady praktycznego zastosowania
1. Galeria obrazów z lazy loading
1// components/quantum-gallery.tsx
2import { useState } from 'react';
3import Image from 'next/image';
4
5const images = [
6 { src: '/images/quantum-city-1.jpg', alt: 'Panorama Metropolis Quantum' },
7 { src: '/images/quantum-city-2.jpg', alt: 'Dzielnica Business Quantum' },
8 { src: '/images/quantum-city-3.jpg', alt: 'Parki Kwantowe' },
9 { src: '/images/quantum-city-4.jpg', alt: 'Architektura Kwantowa' },
10 { src: '/images/quantum-city-5.jpg', alt: 'Transport Kwantowy' },
11 // więcej obrazów...
12];
13
14export default function QuantumGallery() {
15 const [selectedImage, setSelectedImage] = useState(null);
16
17 return (
18 <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
19 <h2 className="text-3xl font-bold mb-6">Galeria Metropolis Quantum</h2>
20
21 {/* Wyświetlanie wybranego obrazu */}
22 {selectedImage && (
23 <div className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50">
24 <div className="max-w-4xl mx-auto p-4">
25 <div className="relative w-full" style={{ height: '80vh' }}>
26 <Image
27 src={selectedImage.src}
28 alt={selectedImage.alt}
29 fill
30 style={{ objectFit: 'contain' }}
31 preload
32 />
33 </div>
34 <button
35 className="absolute top-4 right-4 text-white text-2xl"
36 onClick={() => setSelectedImage(null)}
37 >
38 ×
39 </button>
40 </div>
41 </div>
42 )}
43
44 {/* Siatka obrazów */}
45 <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
46 {images.map((image, index) => (
47 <div
48 key={index}
49 className="relative aspect-square overflow-hidden rounded-lg cursor-pointer hover:opacity-90 transition-opacity"
50 onClick={() => setSelectedImage(image)}
51 >
52 <Image
53 src={image.src}
54 alt={image.alt}
55 fill
56 style={{ objectFit: 'cover' }}
57 sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, (max-width: 1024px) 33vw, 25vw"
58 // Pierwszy obraz jest priorytetowy, pozostałe są ładowane leniwie
59 preload={index === 0}
60 />
61 </div>
62 ))}
63 </div>
64 </div>
65 );
66}2. Responsywny banner z różnymi obrazami dla różnych urządzeń
1// components/quantum-hero.tsx
2import Image from 'next/image';
3
4export default function QuantumHero() {
5 return (
6 <div className="relative">
7 {/* Obraz dla urządzeń mobilnych */}
8 <div className="sm:hidden relative h-[50vh]">
9 <Image
10 src="/images/quantum-hero-mobile.jpg"
11 alt="Metropolis Quantum - Miasto Przyszłości"
12 fill
13 style={{ objectFit: 'cover' }}
14 preload
15 />
16 </div>
17
18 {/* Obraz dla tabletów */}
19 <div className="hidden sm:block md:hidden relative h-[60vh]">
20 <Image
21 src="/images/quantum-hero-tablet.jpg"
22 alt="Metropolis Quantum - Miasto Przyszłości"
23 fill
24 style={{ objectFit: 'cover' }}
25 preload
26 />
27 </div>
28
29 {/* Obraz dla desktopów */}
30 <div className="hidden md:block relative h-[70vh]">
31 <Image
32 src="/images/quantum-hero-desktop.jpg"
33 alt="Metropolis Quantum - Miasto Przyszłości"
34 fill
35 style={{ objectFit: 'cover' }}
36 preload
37 />
38 </div>
39
40 {/* Zawartość nakładkowa */}
41 <div className="absolute inset-0 flex items-center justify-center">
42 <div className="text-center text-white p-4 backdrop-blur-sm bg-black/30 rounded-lg max-w-2xl">
43 <h1 className="text-4xl sm:text-5xl md:text-6xl font-bold mb-4">
44 Metropolis Quantum
45 </h1>
46 <p className="text-xl sm:text-2xl md:text-3xl">
47 Miasto przyszłości czeka na Ciebie
48 </p>
49 </div>
50 </div>
51 </div>
52 );
53}3. Karty produktów z obrazami
1// components/quantum-product-card.tsx
2import Image from 'next/image';
3import { useState } from 'react';
4
5interface ProductCardProps {
6 product: {
7 id: string;
8 name: string;
9 image: string;
10 price: number;
11 description: string;
12 };
13}
14
15export default function ProductCard({ product }: ProductCardProps) {
16 const [isLoading, setIsLoading] = useState(true);
17
18 return (
19 <div className="bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden">
20 <div className="relative h-64 w-full bg-gray-200 dark:bg-gray-700">
21 <Image
22 src={product.image}
23 alt={product.name}
24 fill
25 style={{ objectFit: 'cover' }}
26 sizes="(max-width: 768px) 100vw, 33vw"
27 className={`
28 duration-700 ease-in-out
29 ${isLoading ? 'scale-110 blur-xl grayscale' : 'scale-100 blur-0 grayscale-0'}
30 `}
31 onLoad={() => setIsLoading(false)}
32 />
33 </div>
34 <div className="p-4">
35 <h3 className="text-xl font-semibold mb-2 dark:text-white">{product.name}</h3>
36 <p className="text-gray-600 dark:text-gray-300 mb-2">{product.description}</p>
37 <div className="flex justify-between items-center">
38 <span className="text-lg font-bold dark:text-white">
39 {new Intl.NumberFormat('pl-PL', { style: 'currency', currency: 'PLN' }).format(product.price)}
40 </span>
41 <button className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md">
42 Dodaj do koszyka
43 </button>
44 </div>
45 </div>
46 </div>
47 );
48}Dobre praktyki przy pracy z komponentem Image
- Zawsze określaj wymiary - dla obrazów z atrybutem
srczawsze definiujwidthiheightlub używajfillz kontenerem o określonych wymiarach - Używaj atrybutu
sizes- pomaga w dostarczaniu odpowiednich rozmiarów obrazu dla różnych urządzeń - Priorytetyzuj obrazy "above the fold" - używaj
preload(dawniejpriority) dla najważniejszego obrazu widocznego bez przewijania - Używaj odpowiednich formatów - pozwól Next.js na automatyczną konwersję do WebP/AVIF
- Optymalizuj pod kątem Core Web Vitals - utrzymuj niskie LCP i CLS
- Używaj statycznych importów dla obrazów lokalnych
- Nie nadużywaj
unoptimized- korzystaj tylko w uzasadnionych przypadkach - Używaj znaczących wartości
alt- dla dostępności i SEO - Obsługuj różne formaty - konfiguruj obsługę AVIF i WebP w
next.config.js
Obsługa formatów obrazów w Next.js 16
Next.js obsługuje automatyczną konwersję obrazów do nowoczesnych formatów. Domyślnie, Next.js używa formatu WebP, który oferuje dobrą kompresję przy zachowaniu jakości. Jednak możesz również skonfigurować obsługę formatu AVIF, który oferuje jeszcze lepszą kompresję:
1// next.config.js
2module.exports = {
3 images: {
4 formats: ['image/avif', 'image/webp'],
5 },
6}Porównanie formatów obrazów
| Format | Zalety | Wady | Wsparcie przeglądarek | |--------|--------|------|----------------------| | JPEG | Szeroko wspierany, dobry dla fotografii | Brak transparentności, większy rozmiar niż nowsze formaty | Wszystkie przeglądarki | | PNG | Obsługuje transparentność, bezstratny | Duży rozmiar pliku | Wszystkie przeglądarki | | WebP | Mniejszy rozmiar niż JPEG/PNG, obsługuje transparentność | Niepełne wsparcie w starszych przeglądarkach | ~95% przeglądarek | | AVIF | Najlepsza kompresja, dobra jakość | Ograniczone wsparcie w przeglądarkach, wolniejsze kodowanie | ~70% przeglądarek |
Debugowanie i rozwiązywanie problemów
Problem: Obrazy są rozmyte lub niskiej jakości
Rozwiązanie: Dostosuj parametr quality:
1<Image
2 src="/images/quantum-city.jpg"
3 alt="Panorama Metropolis Quantum"
4 width={1200}
5 height={600}
6 quality={90} // Domyślnie 75
7/>W Next.js 16 wartość quality musi znajdować się na liście images.qualities w next.config. Domyślnie lista zawiera tylko 75, więc bez dopisania 90 Next.js użyje najbliższej dozwolonej wartości, czyli 75:
1// next.config.js
2module.exports = {
3 images: {
4 qualities: [50, 75, 90],
5 },
6};Teraz obraz powstanie w jakości 90, a pozostałe obrazy mogą dalej korzystać z domyślnego 75.
Problem: Przesunięcia układu (Layout Shift) podczas ładowania obrazów
Rozwiązanie: Zawsze określaj wymiary obrazu lub używaj fill z kontenerem o określonych wymiarach:
1<div className="relative w-full aspect-video">
2 <Image
3 src="/images/quantum-city.jpg"
4 alt="Panorama Metropolis Quantum"
5 fill
6 style={{ objectFit: 'cover' }}
7 />
8</div>Problem: Obrazy nie są responsywne na różnych urządzeniach
Rozwiązanie: Używaj atrybutu sizes:
1<Image
2 src="/images/quantum-city.jpg"
3 alt="Panorama Metropolis Quantum"
4 width={1200}
5 height={600}
6 sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
7/>Problem: Obrazy SVG nie są odpowiednio wyświetlane
Rozwiązanie: Dla plików SVG, często najlepszą opcją jest użycie unoptimized:
1<Image
2 src="/images/logo.svg"
3 alt="Logo Metropolis Quantum"
4 width={200}
5 height={200}
6 unoptimized
7/>Optymalizacja obrazów poza komponentem Image
Oprócz komponentu Image, warto również stosować inne techniki optymalizacji obrazów:
1. Optymalizacja obrazów przed dodaniem do projektu
Przed dodaniem obrazów do projektu, warto je zoptymalizować za pomocą narzędzi takich jak:
- ImageOptim
- Squoosh
- TinyPNG
- SVGO (dla plików SVG)
2. Użycie CDN do serwowania obrazów
Korzystanie z CDN (Content Delivery Network) może znacząco przyspieszyć dostarczanie obrazów:
1// next.config.js
2module.exports = {
3 images: {
4 loader: 'akamai',
5 path: 'https://cdn.quantum-city.com',
6 },
7}3. Używanie techniki "art direction" dla różnych urządzeń
1<picture>
2 <source media="(max-width: 640px)" srcSet="/images/banner-mobile.jpg" />
3 <source media="(max-width: 1024px)" srcSet="/images/banner-tablet.jpg" />
4 <source media="(min-width: 1025px)" srcSet="/images/banner-desktop.jpg" />
5 <img src="/images/banner-fallback.jpg" alt="Banner" />
6</picture>4. Używanie techniki "responsive images" z srcset
1<img
2 src="/images/quantum-city.jpg"
3 srcSet="
4 /images/quantum-city-small.jpg 640w,
5 /images/quantum-city-medium.jpg 1024w,
6 /images/quantum-city-large.jpg 1920w
7 "
8 sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
9 alt="Panorama Metropolis Quantum"
10/>Podsumowanie
Optymalizacja obrazów jest kluczowym aspektem tworzenia wydajnych aplikacji webowych. Next.js 16 oferuje potężny komponent Image, który automatycznie zajmuje się wieloma aspektami optymalizacji:
- Automatyczna optymalizacja - konwersja do nowoczesnych formatów (WebP, AVIF)
- Dostosowanie rozmiaru - serwowanie obrazów w odpowiednim rozmiarze dla urządzenia
- Leniwe ładowanie - obrazy są ładowane tylko wtedy, gdy zbliżają się do viewport
- Unikanie przesunięć układu - rezerwacja przestrzeni dla obrazów przed ich załadowaniem
- Wsparcie dla wielu źródeł - łatwe określenie różnych obrazów dla różnych rozdzielczości
Dzięki tym funkcjom, możesz tworzyć aplikacje, które ładują się szybciej, zużywają mniej danych i zapewniają lepsze doświadczenie użytkownika. Podobnie jak inżynierowie Metropolis Quantum optymalizują systemy wyświetlania hologramów i cyfrowych billboardów, tak ty możesz optymalizować obrazy w swojej aplikacji Next.js, aby zapewnić użytkownikom płynne i wydajne doświadczenie.
W następnym rozdziale poznamy różne strategie ładowania obrazów (lazy, eager, priority), które pozwolą jeszcze bardziej dostosować zachowanie obrazów do potrzeb twojej aplikacji.
Kod do tej lekcji: app/page.tsx
1// Next.js Image Component - Optimization Demo
2'use client';
3
4import { useState } from 'react';
5
6// Note: In a real Next.js project, you'd use:
7// import Image from 'next/image';
8// Here we demonstrate the concepts with standard img tags
9
10export default function ImageOptimizationDemo() {
11 const [showComparison, setShowComparison] = useState(false);
12
13 return (
14 <div className="min-h-screen bg-gray-900 text-white p-8">
15 <div className="max-w-4xl mx-auto">
16 <h1 className="text-3xl font-bold mb-2">Image Optimization in Next.js 16</h1>
17 <p className="text-gray-400 mb-8">
18 Automatic optimization, lazy loading, and responsive images
19 </p>
20
21 {/* Traditional vs Next.js Image comparison */}
22 <section className="mb-12">
23 <h2 className="text-xl font-semibold mb-4">Traditional HTML vs Next.js Image</h2>
24
25 <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
26 {/* Traditional approach */}
27 <div className="bg-gray-800 rounded-lg p-6">
28 <h3 className="text-red-400 font-mono mb-3">Traditional {"<img>"}</h3>
29 <pre className="bg-gray-900 p-4 rounded text-sm overflow-x-auto">
30{`<img
31 src="/photo.jpg"
32 alt="City panorama"
33 width="800"
34 height="600"
35/>`}
36 </pre>
37 <ul className="mt-4 space-y-2 text-sm text-gray-400">
38 <li>• No automatic optimization</li>
39 <li>• No lazy loading by default</li>
40 <li>• No responsive sizing</li>
41 <li>• Can cause layout shift (CLS)</li>
42 </ul>
43 </div>
44
45 {/* Next.js Image approach */}
46 <div className="bg-gray-800 rounded-lg p-6">
47 <h3 className="text-green-400 font-mono mb-3">Next.js {"<Image>"}</h3>
48 <pre className="bg-gray-900 p-4 rounded text-sm overflow-x-auto">
49{`import Image from 'next/image';
50
51<Image
52 src="/photo.jpg"
53 alt="City panorama"
54 width={800}
55 height={600}
56 placeholder="blur"
57/>`}
58 </pre>
59 <ul className="mt-4 space-y-2 text-sm text-gray-400">
60 <li>Auto WebP/AVIF conversion</li>
61 <li>Built-in lazy loading</li>
62 <li>Responsive srcset</li>
63 <li>Prevents layout shift</li>
64 </ul>
65 </div>
66 </div>
67 </section>
68
69 {/* Image properties demo */}
70 <section className="mb-12">
71 <h2 className="text-xl font-semibold mb-4">Key Properties</h2>
72 <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
73 <div className="bg-gray-800 rounded-lg p-4">
74 <h3 className="text-blue-400 font-semibold mb-2">fill</h3>
75 <p className="text-sm text-gray-400">
76 Image fills parent container. Use with position: relative on parent.
77 </p>
78 <code className="text-xs text-green-400 mt-2 block">
79 {"<Image fill style={{objectFit: 'cover'}} />"}
80 </code>
81 </div>
82 <div className="bg-gray-800 rounded-lg p-4">
83 <h3 className="text-purple-400 font-semibold mb-2">sizes</h3>
84 <p className="text-sm text-gray-400">
85 Responsive breakpoints for different viewport widths.
86 </p>
87 <code className="text-xs text-green-400 mt-2 block">
88 {'sizes="(max-width: 768px) 100vw, 50vw"'}
89 </code>
90 </div>
91 <div className="bg-gray-800 rounded-lg p-4">
92 <h3 className="text-yellow-400 font-semibold mb-2">placeholder</h3>
93 <p className="text-sm text-gray-400">
94 Show blur or empty placeholder while image loads.
95 </p>
96 <code className="text-xs text-green-400 mt-2 block">
97 {'placeholder="blur" blurDataURL="..."'}
98 </code>
99 </div>
100 </div>
101 </section>
102 </div>
103 </div>
104 );
105}Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. W Tailwind CSS klasa 'flex justify-center items-center' oznacza:
2. CSS-in-JS pozwala na:
Zadania praktyczne w grze
- Edytor kodu
Utwórz CSS z media queries dla mobile-first responsive design (sm, md, lg, xl breakpoints)
- Układanie w poziomie
Ułóż elementy w prawidłowej kolejności: return { → notFound: → true
- Klikanie w kolejności
Ułóż składnię media query z min-width
- Edytor kodu
Utwórz layout strony z headerem, sidebarem, main content i footerem używając CSS Grid