Oğuzhan KARAGÜZEL

OĞUZHAN KARAGÜZEL

Yazılım geliştirici

Görsellerde sizes Niteliği: Tarayıcı Neden Büyük Görsel İndirir?

Yazar: Oğuzhan KARAGÜZEL ·

Görsele srcset ile birkaç farklı boyut verdiniz ve tarayıcının ekrana uygun olanı seçeceğini düşündünüz. Sonra DevTools'u açtınız ve 400 piksellik bir kart görseli için 2400 piksellik dosyanın indiğini gördünüz. Bunun sebebi çoğu zaman eksik ya da yanlış yazılmış bir sizes niteliği. Bu yazıda tarayıcının görsel boyutunu nasıl seçtiğini, sizes'ı nasıl doğru yazacağınızı, ızgara (grid) düzenlerinde işin neden zorlaştığını ve sizes="auto"'nun ne zaman işe yaradığını anlatacağım.

Tarayıcı görseli neye göre seçer?

Bir görselin farklı boyutları genişlik tanımıyla (w) verilir:

HTML
<img src="/img/kart-800.jpg"
     srcset="/img/kart-480.jpg 480w,
             /img/kart-800.jpg 800w,
             /img/kart-1200.jpg 1200w,
             /img/kart-2400.jpg 2400w"
     width="1200" height="630" alt="...">

Tarayıcı hangi dosyayı indireceğine sayfa düzenini hesaplamadan önce karar verir. Bu bilerek yapılmış bir tercih: görsel isteği HTML okunurken, CSS daha inmeden başlasın diye. Ama bu yüzden tarayıcı o anda görselin ekranda ne kadar geniş görüneceğini bilmez. Bunu ona söyleyen şey sizes niteliği.

sizes yoksa tarayıcı görselin ekranın tamamı kadar geniş olacağını varsayar (100vw). Sonra da görselin gösterileceği genişlik × ekranın piksel yoğunluğu değerine eşit ya da ondan büyük olan en küçük dosyayı seçer.

sizes olmazsa ne olur? Bir hesap yapalım

1920 piksel genişliğinde, piksel yoğunluğu 2 olan bir dizüstü ekran düşünün. Sayfadaki içerik alanı en fazla 1200 piksel genişliğinde ve içinde yan yana üç kart var. Her kartın görseli yaklaşık 400 CSS pikseli genişliğinde.

  • Gerçekte gereken: 400 × 2 = 800 piksel. kart-800.jpg yeterli.
  • sizes yokken tarayıcının varsaydığı: 1920 × 2 = 3840 piksel. Bu yüzden en büyük dosya, kart-2400.jpg iniyor.

Yani her kart için gerekenin yaklaşık dokuz katı piksel indiriliyor, dosya boyutu da kabaca o kadar büyüyor. Üç kartlık bir ızgarada bu fark mobil bağlantıda saniyeler demek ve sayfanın en büyük içeriğinin yüklenme süresini (LCP) doğrudan uzatıyor.

sizes'ı doğru yazmak

sizes, virgülle ayrılmış "koşul + genişlik" çiftlerinden oluşur. Tarayıcı soldan sağa ilk uyan koşulu kullanır. Sondaki değerin koşulu yoktur ve hiçbir koşul uymazsa o geçerli olur:

HTML
<img srcset="..."
     sizes="(max-width: 768px) 100vw,
            (max-width: 1200px) 33vw,
            400px"
     ...>

Bunu şöyle okuyabilirsiniz:

  • Ekran 768 pikselden darsa kartlar alt alta dizilir, görsel ekranın tamamı kadardır.
  • 1200 piksele kadar üç sütun vardır, görsel ekranın üçte biri kadardır.
  • Daha geniş ekranlarda içerik alanı 1200 pikselde kalır, görsel en fazla 400 pikseldir.

Birkaç kural işinizi kolaylaştırır:

  • Tam tutturmanız gerekmiyor. sizes bir tahmin. Boşlukları (gap) ve iç boşlukları (padding) hesaba katmasanız da tarayıcı en fazla bir boy büyük dosyayı seçer, bulanık görsel göstermez. Yanılacaksanız büyük tarafta yanılın.
  • Koşulları CSS'teki kırılma noktalarıyla aynı tutun. Izgara 768 pikselde tek sütuna iniyorsa sizes'taki koşul da 768 olmalı.
  • Yüzde değil, vw ya da piksel kullanın. sizes'ta yüzde geçersiz. calc() ise kullanılabiliyor: calc((100vw - 48px) / 3).
  • width ve height'i unutmayın. Hangi dosyanın ineceğini etkilemezler ama tarayıcı görselin yerini önceden ayırır ve sayfa kaymaz (CLS).

Izgaralarda işin zorlaştığı yer: auto-fit

Sütun sayısı sabitse sizes yazmak kolay. Ama günümüzde kart düzenleri çoğu zaman şöyle yazılıyor:

CSS
.kartlar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 24px;
    max-width: 1200px;
}

Burada sütun sayısına CSS değil, ekran genişliği karar veriyor: 1200 piksellik alana en az 320 piksellik üç sütun sığıyor, 700 piksellik alana iki, telefona bir. Kartın genişliği de sütun sayısına göre değişiyor. Bu düzen için mantıklı bir sizes, her aralıkta kartın ulaşabileceği en büyük genişliği vermek:

HTML
sizes="(max-width: 700px) 100vw,
       (max-width: 1040px) 50vw,
       400px"

Bu değerler kesin değil, birer üst sınır. Yine de 100vw varsayımından çok daha doğrular. Bu sitenin altyapısı olan Elevare'de bu hesabı elle yapmıyoruz, sunucu yapıyor. Sayfa oluşturulurken sayfanın kendi CSS'i okunuyor; görselin içinde durduğu ızgaranın sütun sayısı ya da minmax()'taki en küçük sütun genişliği ve kapsayıcının max-width değeri bulunuyor, sizes da buna göre yazılıyor. Boşluklar hesaba katılmadığı için tarayıcı gerekirse bir boy büyük dosyayı seçiyor, küçüğünü asla.

sizes="auto": tahmini tarayıcıya bırakmak

Lazy yüklenen görseller için artık daha kolay bir yol var. Lazy bir görselin isteği zaten sayfa düzeni hesaplandıktan sonra, görsel ekrana yaklaşınca başlıyor. O anda tarayıcı görselin gerçek genişliğini biliyor. sizes="auto" da tarayıcıya "tahmin etme, ölçtüğün genişliği kullan" demek oluyor:

HTML
<img loading="lazy"
     srcset="..."
     sizes="auto, (max-width: 700px) 100vw, 400px"
     width="1200" height="630" alt="...">

İki şeye dikkat edin:

  • Sadece loading="lazy" ile çalışır. İlk ekranda görünen görseller lazy olmamalı (LCP'yi geciktirir). Onlar için sizes'ı yine elle yazmanız gerekiyor.
  • Yedek değer bırakın. sizes="auto"'yu şimdilik Chromium tabanlı tarayıcılar destekliyor. Desteklemeyen tarayıcı auto'yu atlayıp virgülden sonraki değerleri kullanıyor. Bu yüzden auto'yu tek başına değil, arkasına bir tahmin koyarak yazın.

WebP ile birlikte: picture ve source

Aynı görseli WebP ya da AVIF olarak da sunuyorsanız <picture> kullanırsınız. Her <source>'un kendi srcset'i olur; sizes'ı da her birine ayrıca yazmanız gerekir. <img>'deki sizes source'lara kendiliğinden geçmez:

HTML
<picture>
  <source type="image/webp"
          srcset="/img/kart-480.webp 480w, /img/kart-800.webp 800w, /img/kart-1200.webp 1200w"
          sizes="(max-width: 700px) 100vw, 400px">
  <img src="/img/kart-800.jpg"
       srcset="/img/kart-480.jpg 480w, /img/kart-800.jpg 800w, /img/kart-1200.jpg 1200w"
       sizes="(max-width: 700px) 100vw, 400px"
       width="1200" height="630" alt="..." loading="lazy">
</picture>

Çok yapılan bir hata, sizes'ı sadece <img>'ye yazmak. WebP destekleyen bütün güncel tarayıcılar source'u kullandığı için asıl inen dosya yine 100vw varsayımıyla seçiliyor.

Doğru dosyanın indiğini nasıl anlarsınız?

En hızlı yol, tarayıcı konsolunda sayfadaki bütün görselleri tek seferde kontrol etmek:

JavaScript
[...document.images].map(img => ({
  dosya: img.currentSrc.split('/').pop(),
  indirilen: img.naturalWidth,
  gereken: Math.round(img.clientWidth * devicePixelRatio)
}));

indirilen, gereken'in birkaç katıysa o görselin sizes'ı ya eksik ya yanlış. Bir boy büyük çıkması normal, dosya boyutları arasındaki adımlar yüzünden bu kaçınılmaz.

Bir not daha: Lighthouse'taki "Improve image delivery" uyarısı, kazancı görselin ekrandaki CSS boyutuna göre hesaplıyor ve ekranın piksel yoğunluğunu hesaba katmıyor. Bu yüzden 2x ekrana göre doğru seçilmiş bir görselde bile uyarı çıkmaya devam edebilir. Uyarıyı susturmaya uğraşmak yerine yukarıdaki kontrolle gerçekten fazladan veri inip inmediğine bakın.

Sonuç

srcset tek başına yarım bir çözüm. Tarayıcıya görselin ne kadar geniş görüneceğini söyleyen sizes olmazsa çoğu zaman en büyük dosya iniyor. Sabit sütunlu düzenlerde sizes'ı CSS'teki kırılma noktalarına göre yazın, auto-fit ızgaralarında her aralık için bir üst sınır verin, lazy görsellerde sizes="auto"'yu arkasına bir tahmin koyarak kullanın ve <picture> içindeki her source'a sizes yazmayı unutmayın. Görsellerin hangi sırayla indiğini anlattığım Kaynak İpuçları yazısına ve genel bir bakış için Web Sitesi Hızı ve Core Web Vitals yazısına da göz atabilirsiniz.