uurstudios
Tüm yazılar
PerformansGörsel OptimizasyonuNext.js

Görsel optimizasyonu: WebP, AVIF, srcset ve Next.js Image ne yapar?

30 Eylül 2026 5 dk okumaUğur Can Elsun

Bir sitenin ağırlığında en büyük payı neredeyse her zaman görseller alıyor. İşin iyi tarafı, görsel optimizasyonu bir kez düzgün kurulduğunda sonrasında kendi kendine çalışan bir iş. Dört soruya doğru cevap vermek yetiyor: hangi format, hangi boyut, ne zaman yüklenecek ve tarayıcı yer ayırabiliyor mu?

Bu yazıda bu dört soruyu sırayla ele alıyorum, sonra Next.js'in Image bileşeninin bu işin hangi kısmını sizin yerinize yaptığını ve hangisini yapmadığını anlatıyorum.

Format: AVIF, WebP, JPEG

Kısa cevap: fotoğraflar için AVIF, onu desteklemeyen ortamlar için WebP, en sonda JPEG yedeği. Logo, ikon ve düz renkli çizimler için ise SVG.

Portföyümdeki kurumsal site hız çalışmasında aynı ana görseli 800 px genişlikte üç formatta ürettim. Kaynak dosya sharp ile işlendi (AVIF kalite 50, WebP kalite 72, mozjpeg kalite 76):

DosyaBoyut
Eski sitedeki 1600 px JPEG295 KB
800 px JPEG (mozjpeg)56 KB
800 px WebP56 KB
800 px AVIF37 KB
1600 px AVIF124 KB

İki şey dikkat çekiyor. Birincisi, kazancın büyük kısmı formattan değil boyuttan geliyor: aynı JPEG'i doğru genişliğe indirip iyi bir kodlayıcıyla sıkıştırmak bile 295 KB'ı 56 KB'a düşürdü. İkincisi, AVIF bunun üstüne üçte birlik bir kazanç daha sağladı. Galerideki diğer üç görselde de sonuç benzerdi; 800 px AVIF sürümleri 35–38 KB arasında kaldı.

AVIF'in bedeli kodlama süresi: WebP'ye göre belirgin şekilde yavaş üretiliyor. Derleme aşamasında bir kez üretiyorsanız sorun değil, ama her istekte anlık dönüştürme yapan bir sunucuda ilk isteği yavaşlatabilir.

Boyut: srcset ve sizes birlikte çalışır

srcset tarayıcıya elindeki seçenekleri söyler, sizes ise görselin sayfada ne kadar yer kaplayacağını. Tarayıcı bu ikisini ekran genişliği ve piksel yoğunluğuyla birleştirip en uygun dosyayı seçer.

<picture>
  <source type="image/avif"
          srcset="depo-480.avif 480w, depo-800.avif 800w, depo-1200.avif 1200w"
          sizes="(max-width: 640px) 100vw, 565px">
  <source type="image/webp"
          srcset="depo-480.webp 480w, depo-800.webp 800w, depo-1200.webp 1200w"
          sizes="(max-width: 640px) 100vw, 565px">
  <img src="depo-800.jpg" width="800" height="533"
       loading="lazy" decoding="async"
       alt="Tuzla antreposunda paletli raf sistemi">
</picture>

Bu örnek lojistik firması sitesinin galerisinden. sizes şunu söylüyor: ekran 640 px veya daha darsa görsel tam genişlikte, değilse 565 px. Tarayıcı 2x yoğunluklu bir masaüstü ekranda 565 × 2 = 1130 px'lik ihtiyacı görür ve 1200w dosyasını seçer; 390 px genişliğindeki 3x bir telefonda ise yaklaşık 1170 px gerektiği için yine 1200w'yi alır.

En sık görülen hata sizes'ı hiç yazmamak. Yazmazsanız tarayıcı görselin ekran genişliği kadar (100vw) olduğunu varsayar ve üç sütunlu bir ızgaradaki küçük kart görseli için bile en büyük dosyayı indirebilir.

Aynı çalışmada bu dosyaları elle üretmedim; bir betik her kaynak görseli 4 genişlik (480, 800, 1200, 1600) ve 3 formatta çıkarıyor:

for (const w of [480, 800, 1200, 1600]) {
  const base = input.clone().resize({ width: w, withoutEnlargement: true });
  await base.clone().avif({ quality: 50, effort: 6 }).toFile(`${ad}-${w}.avif`);
  await base.clone().webp({ quality: 72, effort: 6 }).toFile(`${ad}-${w}.webp`);
  await base.clone().jpeg({ quality: 76, mozjpeg: true }).toFile(`${ad}-${w}.jpg`);
}

Yükleme sırası ve yer ayırma

Lazy loading her yerde doğru değil

loading="lazy" görseli ekrana yaklaşana kadar indirmez. Ekranın altındaki galeriler, blog listesindeki kapaklar, alt bilgi logoları için ideal. Ama sayfanın en üstündeki büyük görsele koyarsanız tarayıcı onu geç keşfeder ve LCP kötüleşir.

Kural basit:

  • İlk ekrandaki ana görsel: loading yok (varsayılan eager), fetchpriority="high", gerekiyorsa <link rel="preload">.
  • İlk ekrandaki diğer görseller: normal yükleme, öncelik ipucu yok.
  • Ekranın altındaki her şey: loading="lazy".

fetchpriority="high"'ı yalnızca bir görsele verin. Beş görsele birden yüksek öncelik vermek, hiçbirine vermemekle aynı kapıya çıkar.

width, height ve aspect-ratio

<img>'e width ve height verdiğinizde tarayıcı görsel inmeden önce oranını bilir ve yerini ayırır. CSS'te width: 100%; height: auto ile görsel yine esnek kalır, ama sayfa içerik indikçe zıplamaz. Görseli bir kapsayıcıya object-fit: cover ile oturtuyorsanız kapsayıcıya aspect-ratio vermek aynı işi görür. Lojistik firması sitesinde galeri görsellerine boyut ve aspect-ratio eklemek, sonradan gelen bantların düzeltilmesiyle birlikte CLS'yi 0,178'den 0'a indiren adımlardan biriydi.

Next.js Image ne yapar?

next/image yukarıdaki işlerin önemli bir kısmını otomatikleştiriyor. Aşağıdakiler Next.js 16 belgelerine göre:

  • Görseli istek anında yeniden boyutlandırıp sıkıştırır ve sonucu sunucuda önbelleğe alır.
  • Tarayıcının Accept başlığına göre format seçer. Varsayılan liste yalnızca WebP'dir; AVIF istiyorsanız next.config içinde açmanız gerekir.
  • srcset'i kendisi üretir. sizes verirseniz 640w, 750w, 1080w gibi tam bir genişlik listesi, vermezseniz yalnızca 1x ve 2x seçenekleri oluşturur.
  • Varsayılan olarak loading="lazy" kullanır.
  • width ve height ile tarayıcının yer ayırmasını sağlar; yerel dosyayı import ile verirseniz boyutları kendisi okur ve bulanık önizleme (placeholder="blur") üretebilir.
// next.config.js
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
    qualities: [60, 75],
  },
};
import Image from 'next/image';
import kapak from './kapak.jpg';

export function Hero() {
  return (
    <Image
      src={kapak}
      alt="Depo sahasında yükleme yapan forklift"
      sizes="100vw"
      fetchPriority="high"
      loading="eager"
      placeholder="blur"
    />
  );
}

Next.js 16 ile priority özelliği kullanımdan kaldırıldı, yerine preload geldi. Belgeler çoğu durumda preload yerine loading="eager" ya da fetchPriority="high" kullanmayı öneriyor. qualities listesi de 16 ile birlikte zorunlu hale geldi; listede olmayan bir quality değeri en yakın izinli değere yuvarlanıyor.

Next.js Image ne yapmaz?

Bileşen sihirli değil; şu kararlar hâlâ sizde:

  • sizes'ı sizin yerinize tahmin etmez. fill kullanıyorsanız ya da görsel CSS ile esniyorsa sizes yazmak zorundasınız, yoksa gereğinden büyük dosya iner.
  • Hangi görselin LCP olduğunu bilmez. Varsayılan lazy olduğu için ana görseli eager ve yüksek öncelikli işaretlemezseniz LCP geç gelir.
  • Sanat yönetimi (art direction) yapmaz. Mobilde farklı kırpılmış bir görsel göstermek istiyorsanız getImageProps ile kendi <picture> yapınızı kurmanız gerekir.
  • Statik dışa aktarımda (output: 'export') optimizasyon sunucusu yoktur; özel bir loader ya da önceden üretilmiş dosyalar gerekir.
  • SVG'leri optimize etmez; vektör dosyaları olduğu gibi sunulur.
  • İlk istek ücretsiz değildir. Optimize edilmiş sürüm ilk istendiğinde üretilir. Çok sayıda büyük kaynak görseliniz varsa bu ilk isteklerde gecikme ve sunucu yükü demek; yüklemeden önce kaynakları makul bir boyuta (örneğin en fazla 2400 px) indirmek hâlâ iyi bir fikir.

Kontrol listesi

  • Fotoğraflar AVIF ve WebP olarak sunuluyor, JPEG yedeği var.
  • Her görselin birden fazla genişliği var ve sizes görselin gerçek yerleşimini anlatıyor.
  • İlk ekrandaki ana görsel lazy değil, tek yüksek öncelikli görsel o.
  • Ekranın altındaki görseller lazy.
  • Her <img>'de width ve height ya da kapsayıcıda aspect-ratio var.
  • Anlamlı görsellerin alt metni var, süs görsellerinde alt="".
  • Bir bütçe var: kurumsal site hız çalışmasında ana görsel için sınır 60 KB'tı ve her ölçümde kontrol ediliyordu.

Kurulumu bir kez yaptığınızda, yeni eklenen her görsel aynı hattan geçer ve sitenizin ağırlığı zamanla sessizce artmaz.

İlgili yazılar

Bir projeniz mi var?

Fikrinizi anlatın, 24 saat içinde size özel bir teklif ve yol haritasıyla dönüş yapayım.

Teklif Al
WhatsApp