WebP, AVIF ve lazy load ile görsel optimizasyonu

Çoğu sitede sayfa ağırlığının en büyük kısmı görsellerden geliyor. Buna rağmen görsel optimizasyonu genellikle "bir eklenti kurdum, sıkıştırıyor" seviyesinde kalıyor. Oysa asıl kazanç sıkıştırma oranında değil; doğru formatı, doğru boyutu ve doğru yükleme zamanlamasını bir arada kurmakta.

Aşağıda WebP ve AVIF arasında nasıl seçim yaptığımı, HTML tarafını nasıl kurduğumu ve lazy load'u nerede kullanıp nerede asla kullanmadığımı anlatıyorum.

JPEG, WebP ve AVIF

ÖzellikJPEGWebPAVIF
Tarayıcı desteğiEvrenselGüncel tüm büyük tarayıcılarGüncel tüm büyük tarayıcılar
Aynı kalitede dosya boyutuReferansGenellikle daha küçükGenellikle en küçük
Kodlama (encode) hızıHızlıHızlıBelirgin şekilde yavaş
ŞeffaflıkYokVarVar
Tipik kullanımYedek formatGenel amaçlı varsayılanBüyük fotoğraflar, hero görselleri

Boyut karşılaştırması görselin içeriğine göre değişir; bu yüzden kesin bir yüzde vermiyorum. Kendi görsellerinizle deneyip gözle karşılaştırmak en doğrusu. Benim gözlemim şu: fotoğraflarda AVIF, aynı algılanan kalitede genellikle WebP'den daha küçük dosya veriyor; düz renkli grafik ve ekran görüntülerinde fark azalabiliyor. AVIF'in bedeli kodlama süresi. Binlerce görseli yüklenme anında dönüştüren bir sistemde bu ciddi bir CPU yüküdür.

Pratik kararım: yeni görselleri hem AVIF hem WebP olarak üretip <picture> ile sunmak; bunun zahmetli olduğu yerlerde sadece WebP kullanmak.

picture ile yedekli sunum

<picture> içinde tarayıcı, desteklediği ilk <source> türünü seçer. Hiçbirini desteklemiyorsa <img> içindeki JPEG yüklenir. alt, width, height gibi öznitelikler her zaman <img> üzerinde yazılır.

<picture>
  <source type="image/avif"
          srcset="/img/kahve-800.avif 800w, /img/kahve-1600.avif 1600w"
          sizes="(max-width: 800px) 100vw, 800px">
  <source type="image/webp"
          srcset="/img/kahve-800.webp 800w, /img/kahve-1600.webp 1600w"
          sizes="(max-width: 800px) 100vw, 800px">
  <img src="/img/kahve-800.jpg"
       srcset="/img/kahve-800.jpg 800w, /img/kahve-1600.jpg 1600w"
       sizes="(max-width: 800px) 100vw, 800px"
       width="800" height="533"
       loading="lazy" decoding="async"
       alt="French press ile demlenmiş filtre kahve">
</picture>

srcset ve sizes

srcset tarayıcıya elinizdeki görsel genişliklerini, sizes ise görselin sayfada kaç piksel yer kaplayacağını söyler. Tarayıcı ekran genişliği ve piksel yoğunluğuna göre en uygun dosyayı seçer.

Sık yapılan hata, sizes yazmadan w tanımlayıcılı srcset kullanmaktır. Bu durumda tarayıcı görselin tam ekran genişliğinde olduğunu varsayar ve gereğinden büyük dosya indirir. İçerik sütunu en fazla 800 piksel ise bunu sizes içinde açıkça belirtin.

Kaç genişlik üretmelisiniz? Ben çoğu içerik görseli için üç-dört genişlikle yetiniyorum: mobil, tablet, masaüstü ve yüksek yoğunluklu ekranlar için bir büyük sürüm.

width ve height: kaymayı önlemek

width ve height öznitelikleri, tarayıcının görsel inmeden önce yer ayırmasını sağlar. CSS'te max-width: 100%; height: auto; ile birlikte kullanıldığında görsel esnek kalır ve oran korunur. Bu iki özniteliği yazmamak, sayfa kaymasının (CLS) en yaygın sebebidir. Konunun ayrıntıları için Sayfa kayması (CLS) nasıl sıfırlanır? yazısına bakabilirsiniz.

Lazy load: sadece görünür alanın altında

loading="lazy", görselin indirilmesini kullanıcı ona yaklaşana kadar erteler. Görünür alanın altındaki görseller için harika; ama görünür alandaki, özellikle LCP elemanı olan görsel için tam tersi etki yapar. Tarayıcı görselin görünür olduğunu anlamak için layout'u beklemek zorunda kalır ve LCP gecikir.

Benim kurallarım:

  • Hero ve ilk ekrandaki ana görsel: loading="lazy" yok, fetchpriority="high" var.
  • İlk ekranın altındaki içerik görselleri: loading="lazy".
  • Logo gibi küçük ve hemen görünen görseller: lazy değil.
  • decoding="async": büyük görsellerin çözümlenmesinin ana iş parçacığını bekletmemesi için ekleyebilirsiniz.
<!-- LCP görseli: öncelikli ve tembel değil -->
<img src="/img/hero-1200.webp" width="1200" height="600"
     fetchpriority="high" alt="Search Console performans raporu ekranı">

SEO açısından bir not: tarayıcının kendi loading="lazy" özelliği Googlebot ile sorunsuz çalışır. Ama görsel URL'sini data-src gibi bir öznitelikte tutup sadece kaydırma olayında gerçek src'ye taşıyan eski JavaScript kütüphaneleri, görselin keşfedilmemesine yol açabilir. Mümkünse yerel lazy load kullanın. LCP'nin diğer parçaları için LCP'yi 2,5 saniyenin altına indirmek yazısına bakın.

Komut satırında dönüştürme

Birkaç görsel için tarayıcıda çalışan WebP dönüştürücü aracını kullanabilirsiniz. Toplu iş için komut satırını tercih ediyorum. cwebp (libwebp) ve avifenc (libavif) araçlarıyla bir klasördeki tüm JPEG'leri dönüştüren kısa bir betik:

donustur.sh
#!/usr/bin/env bash
# Klasördeki JPEG dosyalarını 800 ve 1600 px genişlikte WebP ve AVIF'e dönüştürür
set -euo pipefail
shopt -s nullglob  # eşleşen dosya yoksa döngü hiç çalışmaz

for f in *.jpg; do
  ad="${f%.jpg}"
  for w in 800 1600; do
    # Önce yeniden boyutlandır (ImageMagick 7), sonra dönüştür
    magick "$f" -resize "${w}x>" -quality 90 "tmp-${w}.png"
    cwebp -q 80 "tmp-${w}.png" -o "${ad}-${w}.webp"
    avifenc -q 60 -s 6 "tmp-${w}.png" "${ad}-${w}.avif"
    rm "tmp-${w}.png"
  done
done

-resize "800x>" ifadesi görseli sadece 800 pikselden genişse küçültür; küçük görselleri büyütmez. avifenc için -q parametresi libavif'in 1.0 ve sonraki sürümlerinde var; eski sürümlerde kalite --min ve --max ile ayarlanıyordu. -s hız ayarıdır: düşük değer daha yavaş ama daha verimli kodlama demek. Kalite değerleri başlangıç noktasıdır; kendi görsellerinizde gözle kontrol ederek ayarlayın.

Tek bir dosya için ImageMagick de yeterli: magick girdi.jpg -resize 1200x -quality 80 cikti.webp.

Görsel SEO'su: dosya adı ve alt metin

Google'ın görsel SEO belgeleri birkaç temel noktayı vurgular:

  • Dosya adı: IMG_4521.jpg yerine french-press-kahve.jpg gibi kısa ve açıklayıcı bir ad. Türkçe karakter yerine ASCII karşılıklarını kullanmak URL'lerdeki kodlama karmaşasını önler.
  • Alt metin: Görseli göremeyen biri için ne gösterdiğini anlatan kısa bir cümle. Anahtar kelime doldurmak yerine görseli tarif edin. Dekoratif görsellerde alt="" bırakın.
  • Bağlam: Görselin yakınındaki metin ve başlık, Google'ın görseli anlamasına yardım eder.
  • Desteklenen formatlar: Google'ın belgelerinde listelenen formatlar arasında WebP ve AVIF de var; yine de güncel listeyi belgelerden kontrol edin.

Görsel site haritası isteğe bağlıdır. Görseller sayfa HTML'inde normal <img> olarak bulunuyorsa Google bunları zaten keşfeder. JavaScript ile yüklenen veya ayrı bir CDN alan adında duran görseller için görsel site haritası faydalı olabilir; Google yalnızca image:loc etiketini kullanıyor, eski başlık ve açıklama etiketleri artık desteklenmiyor.

CDN ve görsel servisleri

Görsel sayısı yüksek sitelerde, dönüştürme ve boyutlandırmayı istek anında yapan bir görsel servisi veya CDN kullanmak mantıklı olabilir. Tarayıcının Accept başlığına göre AVIF veya WebP döndürürler. Dikkat edilmesi gereken iki nokta var: görsel URL'lerinin sabit kalması (sürekli değişen parametreler Google'ın görseli yeniden keşfetmesine yol açar) ve servisin Vary başlığını doğru göndermesi. Cloudflare tarafındaki seçenekler için Cloudflare ile hızlanmak yazısına göz atabilirsiniz.

Kontrol listesi

  • Yeni görseller AVIF ve/veya WebP olarak, JPEG yedekli üretiliyor.
  • srcset ile birlikte her zaman doğru sizes yazılıyor.
  • Tüm görsellerde width ve height var.
  • LCP görselinde loading="lazy" yok, fetchpriority="high" var.
  • İlk ekranın altındaki görsellerde yerel loading="lazy" kullanılıyor.
  • Dosya adları açıklayıcı, alt metinler görseli tarif ediyor.
  • Görsel URL'leri sabit; CDN kullanılıyorsa Vary ve önbellek başlıkları kontrol edildi.

Comments / questions

If you have a question about any topic or wish to contact me: Telegram or send an email to [email protected] Thanks!

Related pages