Uzun bir ürün listesi ya da içerik yoğun bir blog sayfası açıldığında tarayıcı, ziyaretçinin asla göremeyeceği onlarca görseli de indirir. Lazy loading, bu görselleri ilk yüklemeden çıkarıp ekrana yaklaştıklarında istemenin adıdır ve bugün bunu yapmak için tek bir HTML özniteliği yeterlidir: loading="lazy". Doğru uygulandığında ilk yükte inen bayt miktarı belirgin biçimde düşer, tarayıcının ağ kuyruğu boşalır ve gerçekten görünen içerik daha erken gelir.
Ama bu özniteliğin bir de ters etkisi var ve sahada gördüğüm en yaygın performans hatalarından biri tam olarak budur: sayfanın en üstündeki büyük görseli lazy yapmak. O görsel çoğu zaman LCP elementidir; geciktirdiğinizde Core Web Vitals puanınızı doğrudan kötüleştirirsiniz. Bu rehberde lazy loading'in nasıl çalıştığını, hangi görsellere uygulanıp hangilerine kesinlikle uygulanmayacağını, fetchpriority ve decoding özniteliklerinin buradaki rolünü, arka plan görselleri için IntersectionObserver çözümünü ve düzen kaymasını nasıl önleyeceğinizi anlatacağım.
Lazy Loading Ne Yapıyor, Ne Kazandırıyor#
Varsayılan davranışta tarayıcı, HTML'i ayrıştırırken karşılaştığı her img etiketi için hemen bir istek açar. Sayfanın 3000 piksel aşağısındaki görsel ile hero görseli arasında öncelik farkı yoktur; ikisi de aynı bant genişliği için yarışır. Lazy loading bu davranışı değiştirir: tarayıcı görselin ekrana ne kadar uzak olduğuna bakar ve yakınlaşana kadar isteği ertelemez, hiç açmaz.
Kazanç iki yerde görülür. Birincisi ilk yükte inen toplam bayt: 40 görselli bir kategori sayfasında ilk ekranda 6 görsel varsa geri kalan 34'ü hiç indirilmez ve ziyaretçi sayfayı yarıda bırakırsa hiç indirilmemiş olarak kalır. İkincisi bant genişliği rekabetidir; kritik kaynaklar (CSS, hero görseli, yazı tipleri) daha az yarışmayla daha erken iner.
| Senaryo | Lazy kapalı | Lazy açık | Not |
|---|---|---|---|
| 40 görselli kategori sayfası | 40 istek | 6-10 istek | En büyük kazanç burada |
| 5 görselli kurumsal ana sayfa | 5 istek | 4-5 istek | Kazanç ihmal edilebilir |
| Hero görseli lazy yapılmış | — | LCP kötüleşir | Doğrudan zarar |
| YouTube gömülü videolar | Her biri ağır | İstek yok | iframe lazy çok etkili |
Tabloda görülebileceği gibi lazy loading her sayfada kazanç üretmez. Az görselli, kısa bir sayfada uğraşmaya değmez; hatta hero görseline yanlışlıkla uygulanırsa net zarar üretir. Kazanç, uzun ve görsel yoğun sayfalarda ortaya çıkar.
Yerleşik loading Özniteliği#
Bugün için doğru başlangıç noktası tarayıcının kendi desteğidir. Ne kütüphane ne eklenti gerekir:
<!-- Ekranın altında kalan bir liste görseli -->
<img src="/img/urun-12.jpg" alt="Ürün 12"
width="600" height="600" loading="lazy" decoding="async">
loading özniteliğinin üç değeri vardır ve pratikte ikisi kullanılır. lazy, görsel görünüm alanına yaklaşana kadar isteği açmamayı söyler. eager, varsayılan davranıştır; hemen indir demektir ve genellikle yazmaya gerek yoktur, ama bir şablonun her görsele otomatik lazy eklediği durumlarda kritik görseli kurtarmak için açıkça yazmak işe yarar. Üçüncü değer auto tarayıcıya bırakır ve öngörülebilir olmadığı için önerilmez.
Yanına yazdığım decoding="async" özniteliği farklı bir işe yarar ve ikisi karıştırılır: loading indirmeyi, decoding ise indirilmiş görselin çözülmesini yönetir. async, çözme işleminin ana iş parçacığını bloklamamasını söyler. Uzun listelerde kaydırma akıcılığına olumlu etkisi vardır ve yan etkisi yoktur.
iframe etiketleri de aynı özniteliği destekler ve buradaki kazanç genellikle görsellerden büyüktür, çünkü gömülü bir video oynatıcı yüzlerce kilobayt JavaScript getirir:
<!-- Gömülü video: ekrana gelene kadar hiçbir kaynak inmez -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
width="560" height="315" loading="lazy"
title="Tanıtım videosu" allowfullscreen></iframe>
Asıl Kural: Hangi Görsel Lazy Olmamalı#
Bu bölüm bu yazının en önemli kısmı. Kural şu: ilk ekranda (viewport içinde) görünen hiçbir görsel lazy olmamalıdır. Özellikle de LCP elementi olan büyük hero görseli.
Sebebi tarayıcının çalışma biçiminde. Tarayıcının bir ön tarayıcısı (preload scanner) vardır; HTML gelmeye başlar başlamaz belgeyi tarayıp bulduğu kaynakları CSS ve JavaScript beklemeden indirmeye başlar. loading="lazy" yazdığınız anda bu görsel ön tarayıcının kapsamından çıkar; artık tarayıcının düzeni hesaplayıp görselin nerede olduğunu bilmesi gerekir. Yani indirme, düzen hesabından sonraya kayar. Hero görseli için bu, LCP'ye eklenen yüzlerce milisaniye demektir.
Doğru kurulum tam tersidir: kritik görseli açıkça öne çıkarın.
<!-- Sayfanın en üstündeki büyük görsel: geciktirme, aksine önceliklendir -->
<img src="/img/hero-1600.jpg"
srcset="/img/hero-800.jpg 800w, /img/hero-1600.jpg 1600w"
sizes="(max-width: 768px) 100vw, 1200px"
alt="Kampanya görseli"
width="1600" height="900"
fetchpriority="high" decoding="async">
fetchpriority="high" özniteliği tarayıcıya "bu kaynağı diğerlerinin önüne al" der. Görseller varsayılan olarak düşük öncelikle indirilir; hero görselinde bu değeri yükseltmek çoğu sitede ölçülebilir bir LCP kazancı üretir. Bunu bir tane, en fazla iki görselde kullanın — her şeyi yüksek öncelikli yaparsanız hiçbir şey öncelikli olmaz.
Pratik bir yöntem olarak şunu uygulayın: sayfanın ilk ekranındaki görselleri sayın (mobilde genelde 1-3 tanedir), onlara loading yazmayın ya da eager yazın, LCP adayına fetchpriority="high" ekleyin, geri kalan her şeye lazy verin. LCP'yi hangi elementin belirlediğini ve nasıl ölçeceğinizi LCP nasıl iyileştirilir yazısında ayrıntısıyla anlatıyorum.
Düzen Kaymasını Önlemek#
Lazy loading'in ikinci klasik yan etkisi düzen kaymasıdır. Görsel yüklenene kadar tarayıcı onun ne kadar yer kaplayacağını bilmiyorsa, o alanı sıfır yükseklikle geçer; görsel indiğinde altındaki içerik aşağı itilir. Ziyaretçi tam o anda bir bağlantıya tıklıyorsa yanlış yere basar.
Çözüm basittir ve iki parçadan oluşur. Birincisi, width ve height özniteliklerini her zaman yazmak. Modern tarayıcılar bu iki sayıdan en-boy oranını hesaplar ve görsel gelmeden önce doğru yüksekliği ayırır:
<img src="/img/urun.jpg" alt="Ürün" width="800" height="600" loading="lazy">
İkincisi, CSS'te görseli esnetiyorsanız oranı korumak:
/* Öznitelikten gelen oran korunsun, genişlik kapsayıcıya uysun */
img {
max-width: 100%;
height: auto;
}
/* Sabit oranlı kutucuklarda daha açık bir çözüm */
.urun-gorseli {
aspect-ratio: 4 / 3;
object-fit: cover;
width: 100%;
}
height: auto satırı olmadan width/height özniteliği görselin gerçek yüksekliğini zorlar ve responsive düzende bozulma yaratır; bu yüzden ikisi birlikte kullanılır. Düzen kaymasının diğer kaynaklarını ve ölçüm yöntemini CLS düzen kayması nasıl düzeltilir yazısında bulabilirsiniz. Aynı görselin farklı boyutlarını sunuyorsanız srcset kurulumunu responsive görseller: srcset ve sizes rehberiyle birlikte kurun; ikisi birlikte çalışır ve loading="lazy" bu kurulumu bozmaz.
Arka Plan Görselleri ve IntersectionObserver#
loading özniteliği yalnızca img ve iframe etiketlerinde çalışır. CSS ile verilen background-image bunun kapsamında değildir ve tarayıcı bu görselleri, ilgili CSS kuralı bir elemanla eşleştiği anda indirir. Ağır bir arka plan görseliniz sayfanın altındaysa bunu geciktirmek için JavaScript gerekir.
Doğru araç IntersectionObserverdır; kaydırma olayını dinleyip her karede hesap yapan eski yöntemlerin aksine tarayıcının kendi kesişim mekanizmasını kullanır ve neredeyse hiç maliyeti yoktur:
<section class="tanitim" data-arkaplan="/img/genis-arkaplan.jpg"></section>
.tanitim {
min-height: 420px;
background-color: #eef2f7; /* görsel gelene kadar boş görünmesin */
background-size: cover;
background-position: center;
}
Gözlemciyi kuran betik şöyle olabilir:
// Ekrana 300 piksel kala arka planı yükle
const gozlemci = new IntersectionObserver((girisler, gozlem) => {
girisler.forEach((giris) => {
if (!giris.isIntersecting) return;
const el = giris.target;
el.style.backgroundImage = `url("${el.dataset.arkaplan}")`;
gozlem.unobserve(el); // bir kez yükle, tekrar dinleme
});
}, { rootMargin: "300px 0px" });
document.querySelectorAll("[data-arkaplan]").forEach((el) => gozlemci.observe(el));
rootMargin değeri, görsel ekrana girmeden ne kadar önce yükleneceğini belirler. Çok küçük bir değer kullanıcının boş bir alan görmesine yol açar; çok büyük bir değer ise lazy loading'in anlamını yok eder. 200-400 piksel aralığı çoğu düzen için makuldür.
JavaScript kapalıysa arka planın hiç görünmeyeceğini unutmayın; bu yüzden bu tekniği yalnızca dekoratif görsellerde kullanın. Anlam taşıyan bir görsel her zaman img etiketiyle işaretlenmelidir — hem erişilebilirlik hem arama motorları için.
WordPress ve Eklenti Tarafı#
WordPress, belirli bir sürümden itibaren içerik görsellerine loading="lazy" özniteliğini otomatik ekler. Yani hiçbir şey yapmadan temel lazy loading'iniz vardır. Buradaki mesele ekleme değil, doğru görselden kaldırmaktır: WordPress ilk birkaç görseli atlamaya çalışır ama tema yapınıza göre hero görselini de lazy yapabilir.
Kontrol etmenin en hızlı yolu sayfanın kaynağına bakmaktır:
# Ana sayfadaki ilk beş img etiketini ve loading özniteliklerini gör
curl -s https://firmaniz.com/ | grep -o '<img[^>]*>' | head -n 5
İlk sıradaki büyük görselde loading="lazy" görüyorsanız düzeltilmesi gereken bir durum var demektir. Tema geliştiricisiyseniz o görseli çıkaran şablon dosyasında özniteliği eager yapabilir ya da wp_get_attachment_image çağrısına 'loading' => 'eager', 'fetchpriority' => 'high' argümanlarını verebilirsiniz.
Bir performans eklentisi kullanıyorsanız çoğunun kendi lazy loading modülü vardır ve bunlar genellikle JavaScript tabanlıdır. İki modülü aynı anda açık bırakmak (tarayıcının yerleşik özniteliği + eklentinin JavaScript'i) çakışmaya ve görsellerin geç ya da hiç yüklenmemesine yol açabilir; birini seçin. LiteSpeed sunucusundaysanız bu ayarların nerede olduğunu LiteSpeed Cache WordPress yazısında bulabilirsiniz. Değişikliğin etkisini ölçmek için ise GTmetrix ile WordPress hız testi yazısındaki önce-sonra karşılaştırma yöntemini kullanın.
Sık Yapılan Hatalar#
Her görsele topluca lazy eklemek. Bir tema fonksiyonu ya da eklenti ile "tüm görsellere loading=lazy ekle" demek en sık karşılaştığım hatadır. Bu, ilk ekrandaki görselleri de kapsar ve LCP'yi doğrudan kötüleştirir. Kural her zaman "ilk ekran hariç" olmalıdır.
width ve height yazmadan lazy kullanmak. Görsel geldiğinde sayfa zıplar ve CLS puanınız bozulur. Bu ikisi lazy loading'in ayrılmaz parçasıdır, isteğe bağlı değildir.
İki lazy mekanizmasını üst üste çalıştırmak. Tarayıcının yerleşik özniteliği ile bir JavaScript kütüphanesini aynı anda kullanmak, src özniteliğinin data-srce taşındığı kurulumlarda görsellerin hiç yüklenmemesine yol açabilir. Birini kapatın.
fetchpriority="high" özniteliğini her yere yazmak. Öncelik göreceli bir kavramdır; on görselin hepsi yüksek öncelikliyse sıralama yine varsayılan hâline döner ve hiçbir kazanç elde edemezsiniz. En fazla bir ya da iki kaynakta kullanın.
Arka plan görsellerini img yerine CSS ile vermek. Anlam taşıyan bir görseli background-image ile koyduğunuzda hem lazy loading için JavaScript'e mecbur kalırsınız hem de arama motorları ve ekran okuyucular o görseli göremez. Dekoratif olmayan her görsel img olmalıdır.
Sonucu doğrulamamak. Değişiklikten sonra tarayıcı geliştirici araçlarının Network sekmesinde sayfayı açın, aşağı kaydırmadan kaç görselin indiğine bakın. Kaydırdıkça yeni isteklerin belirmesi lazy loading'in çalıştığının kesin işaretidir.
Sıkça Sorulan Sorular#
loading="lazy" tüm tarayıcılarda çalışır mı#
Evet, loading özniteliği artık tüm modern masaüstü ve mobil tarayıcılarda desteklenir. Desteklemeyen çok eski bir tarayıcı ise bilinmeyen özniteliği görmezden gelir ve görseli normal şekilde, yani hemen yükler. Bu, bozulmayan bir geri dönüş anlamına gelir: en kötü durumda kullanıcı optimizasyondan yararlanamaz, hiçbir şey kırılmaz. Bu yüzden ek bir JavaScript kütüphanesine gerek yoktur.
Hangi görsellere lazy loading uygulamamalıyım#
Sayfanın ilk ekranında, yani ziyaretçi hiç kaydırmadan gördüğü alanda bulunan hiçbir görsele uygulamayın. Özellikle LCP elementi olan büyük hero görselini geciktirmek doğrudan Core Web Vitals puanınızı düşürür, çünkü lazy görseller tarayıcının ön tarayıcısı tarafından erkenden indirilemez. Logolar, üst menüdeki simgeler ve ilk kart satırındaki görseller de bu kapsamdadır. Geri kalan her şeye rahatlıkla uygulayabilirsiniz.
Lazy loading SEO'ya zarar verir mi#
Yerleşik loading="lazy" özniteliğini kullandığınızda hayır. Arama motoru tarayıcıları bu özniteliği anlar ve görseli görüntü alanına getirerek yükler. Risk, src yerine data-src kullanan ve tamamen JavaScript'e bağlı eski kütüphanelerdedir; JavaScript çalıştırılmazsa görsel hiç indekslenmez. Bu yüzden mümkün olan her yerde tarayıcının kendi desteğini kullanın ve img etiketinde gerçek bir src bırakın.
Lazy loading sayfayı ne kadar hızlandırır#
Kazanç sayfadaki görsel sayısına doğrudan bağlıdır. Ekranın altında onlarca görsel bulunan kategori, galeri ve uzun blog sayfalarında ilk yükte inen bayt miktarı büyük ölçüde düşer ve fark ölçülebilir olur. Buna karşılık beş görselli kısa bir kurumsal sayfada kazanç ihmal edilebilir düzeydedir. Gömülü video içeren sayfalarda ise iframe tarafındaki kazanç genellikle görsellerden daha büyüktür.
Arka plan görsellerini nasıl lazy yüklerim#
loading özniteliği yalnızca img ve iframe etiketlerinde çalışır, CSS background-image bunun dışındadır. Bunun için IntersectionObserver ile küçük bir betik yazmanız gerekir: görsel yolunu data- özniteliğinde tutar, eleman ekrana yaklaştığında style.backgroundImage değerini atarsınız. rootMargin değerini 200-400 piksel aralığında tutmak, kullanıcının boş alan görmesini engeller. Bu yöntemi yalnızca dekoratif görsellerde kullanın.
fetchpriority ile loading arasındaki fark nedir#
İkisi zıt yönde çalışan iki ayrı öncelik aracıdır. loading="lazy" bir kaynağı geciktirir, hatta ekrana yaklaşana kadar hiç istemez. fetchpriority="high" ise bir kaynağı diğerlerinin önüne alır ve daha erken indirilmesini sağlar. Aynı görsele ikisini birlikte yazmak çelişkilidir; hero görselinde fetchpriority="high" ve lazy olmaması, liste görsellerinde ise yalnızca loading="lazy" doğru kombinasyondur.
Kapanış#
Lazy loading, tek bir öznitelikle büyük kazanç veren ama yanlış yere yazıldığında aynı büyüklükte zarar veren bir araç. Aklınızda kalması gereken dört alışkanlık şunlar: ilk ekrandaki hiçbir görseli geciktirmeyin ve LCP adayına fetchpriority="high" verin, geri kalan her görsele ve gömülü iframelere loading="lazy" yazın, width ile height özniteliklerini istisnasız her görselde bulundurun ve iki farklı lazy mekanizmasını aynı anda çalıştırmayın. Değişiklikten sonra Network sekmesinde kaydırmadan kaç isteğin gittiğine bakarak sonucu doğrulayın.
Görsel yoğun bir katalog ya da uzun içerik sayfaları işletiyorsanız, bu optimizasyonların altında hızlı yanıt veren bir sunucu olması gerekir; LiteSpeed ve sunucu tarafı önbellekleme sunan WordPress hosting ve e-ticaret hosting paketlerimiz bu zemini sağlar. Kendi web sunucusu ve önbellek yapılandırmanızı yönetmek isterseniz tam root erişimli VDS sunucularımıza, kurulumu bize bırakmak isterseniz sunucu yönetimi hizmetimize bakabilirsiniz.