Otomatik dönen carousel bileşenleri LCP, CLS ve INP üzerinde ciddi baskı yaratabilir. Birinci slayta preload, geri kalanlarına lazy loading, aspect-ratio kutusu ve CSS geçişi bir arada uygulandığında bu yük büyük ölçüde azalır.
Görsel Carousel ve Slider Performansı Nasıl Optimize Edilir?
Carousel ve slider bileşenleri, tasarım açısından çekici görünse de web performansı üzerinde beklenmedik ağır bir baskı yaratabilir. Otomatik dönen bir slideshow, tek başına LCP puanını düşürebilir, düzen kaymasına (CLS) zemin hazırlayabilir ve kullanıcı etkileşimlerine verilen yanıt süresini (INP) bozabilir. Sorun, carousel'in var olması değil; genellikle yanlış yapılandırılmış olmasıdır.
Bu bileşenler aynı anda birden fazla büyük görseli yükler, JavaScript kütüphanelerine bağımlı olur ve sayfa içindeki en büyük içerik öğesini tahmin edilemez biçimde değiştirir. Performans bütçesi kısıtlı sayfalar için bu etki küçümsenemez. Doğru yapılandırma, carousel'i tamamen kaldırmadan bu sorunların büyük bölümünü ortadan kaldırabilir.
Carousel LCP, CLS ve INP'yi aynı anda zorlar: ilk slayt keşfi, boyutsuz slayt kutusu ve JS kütüphanesinin ana iş parçacığı maliyeti. CSS geçişi, bu üç baskının bir kısmını kütüphane olmadan çözer; hepsini değil.
Carousel neden performans sorununa dönüşür
Carousel bileşeni yapısal olarak birden fazla büyük görseli barındırır. Çoğu uygulama tüm slaytları başlangıçta DOM'a ekler; yalnızca görünür olan gösterilir, diğerleri display: none veya visibility: hidden ile gizlenir. Gizlenmek, yüklenmemek demek değildir.
Tarayıcı bir <img> etiketini gördüğünde, loading="lazy" yoksa ağ isteğini hemen başlatır. Beş slaytlık bir carousel, açılışta beş büyük görsel isteği tetikleyebilir; bunların dördü kullanıcının hiç görmeyebileceği kaynaklardır. Bu durum bant genişliğini tüketir ve LCP için gerçekten kritik olan birinci slayt görselinin yüklenmesini geciktirir.
JavaScript kütüphanelerine dayanan carousel'lar ise ana iş parçacığını (main thread) uzun görevlerle tıkar. Otomatik geçiş mantığı, dokunma ve kaydırma dinleyicileri, animasyon döngüleri bir araya geldiğinde INP skorunu olumsuz etkileyen bir birikim oluşur. Yük tek bir yerden gelmez; parça parça gelir ve toplamda ağır bir hesap çıkarır.
LCP ve carousel: ilk slayt neden ayrı ele alınmalı
LCP, viewport'ta görünen en büyük içerik öğesinin yüklenme süresini ölçer. Carousel'lerde bu öğe çoğunlukla birinci slaytın büyük görseli olur. Şaşırtıcı olan şu: birinci slayt görseli, carousel doğru yapılandırılmadan LCP için en avantajlı konumda olabilecekken tam tersi bir etkiye yol açabilir.
Birinci slayt görseline loading="lazy" eklemek sık yapılan hatalardan biridir. Lazy loading, viewport dışındaki öğeler için tasarlanmıştır; birinci slayt her zaman viewport içindedir. loading="lazy" eklemek tarayıcıya "bu görseli daha sonra yükle" demektir, bu da LCP süresini doğrudan uzatır.
Birinci slayt görseli için doğru yapı şöyledir: loading niteliği ya hiç eklenmez (tarayıcı varsayılanı eager'dır) ya da <link rel="preload"> ile fetchpriority="high" birlikte kullanılır.
<link rel="preload" as="image" href="slide-1.webp" fetchpriority="high">
Bu tek satır, tarayıcıya kaynağı erken keşfetmesini ve ağ sırasında öncelik vermesini söyler. İkinci, üçüncü ve sonraki slayt görselleri ise loading="lazy" almalıdır; böylece başlangıç yükünden çıkar ve yalnızca o slayta geçildiğinde ağ isteği yapılır.
CLS ve aspect-ratio kutusu
CLS, sayfadaki beklenmedik düzen kayışlarını ölçer. Carousel bileşeni iki farklı biçimde CLS kaynağına dönüşebilir.
Birincisi, görsel boyutu belirtilmediğinde gerçekleşir. Görsel ağdan gelip render edildiği anda kap büyür veya küçülür, altındaki içerik kayar. Bu sorun carousel dışındaki görsellerde de vardır; ancak carousel'deki görseller genellikle sayfanın en büyük öğeleri olduğundan etki daha belirgin olur.
İkincisi, slayt geçişleri sırasında ortaya çıkar. Geçiş animasyonu layout'u yeniden hesaplamayı tetiklerse ya da slayt yükseklikleri birbirinden farklıysa her otomatik geçişte küçük bir CLS birikebilir.
Her iki sorunu da çözen yaklaşım, aspect-ratio ile sabit bir kap tanımlamaktır:
.carousel-container {
aspect-ratio: 16 / 9;
overflow: hidden;
position: relative;
width: 100%;
}
.carousel-slide {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.carousel-slide img {
width: 100%;
height: 100%;
object-fit: cover;
}
Bu yapıda kap, görsel yüklenmeden önce alanını kaplar. Görsel geldiğinde layout bozulmaz. aspect-ratio desteği tüm modern tarayıcılarda eksiksizdir. Ek olarak, her <img> etiketine width ve height HTML nitelikleri eklemek tarayıcıya CSS yüklenmeden önce bile boyut ipucu verir.
INP ve JavaScript carousel maliyeti
INP, kullanıcının etkileşiminden bir sonraki boya aşamasına kadar geçen süreyi ölçer. Carousel bileşenlerinde INP iki noktada baskı altına girer: otomatik geçiş zamanlayıcıları ve etkileşim işleyicileri.
Hızlı bir soru: kullanıcı carousel ilerleme düğmesine tıkladığında tarayıcı ne yapıyor? Yanıt süresi yalnızca tıklama işleyicisine değil, o anda çalışan tüm görevlere bağlıdır. setInterval veya requestAnimationFrame ile çalışan otomatik geçiş döngüleri, her tetiklenişte main thread'e görev ekler. Kullanıcı tam bu noktada bir düğmeye basarsa tarayıcı etkileşime yanıt vermeyi geciktirebilir.
Dokunma ve kaydırma olaylarını izleyen dinleyiciler de katkıda bulunur. Pasif olmayan ({ passive: false }) dinleyiciler scroll performansını doğrudan etkiler. Kaydırma dinleyicilerini pasif olarak işaretlemek basit ama somut bir adımdır:
container.addEventListener('touchstart', handler, { passive: true });
Ağır animasyon kütüphanelerinde bu sorunlar katlanır. Kütüphane başlatma maliyeti, parse ve yürütme süresi, olay delegasyonu katmanları bir araya gelir. Kütüphane seçiminde bundle boyutu ve main thread kullanımı göz önünde bulundurulmalıdır; CSS tabanlı bir yapı bu yükü büyük ölçüde ortadan kaldırır.
CSS geçişiyle kütüphanesiz carousel
CSS geçişleri ve @keyframes animasyonları GPU tarafından işleneceğinden main thread baskısı yaratmaz. Basit bir otomatik carousel için JavaScript yalnızca zamanlayıcı ve sınıf değiştirme göreviyle sınırlı tutulabilir; animasyonun kendisi CSS motoruna devredilir.
.carousel-track {
display: flex;
transition: transform 0.4s ease;
will-change: transform;
}
.carousel-slide {
flex: 0 0 100%;
}
let current = 0;
const slides = document.querySelectorAll('.carousel-slide');
const track = document.querySelector('.carousel-track');
function goTo(index) {
current = index % slides.length;
track.style.transform = `translateX(-${current * 100}%)`;
}
setInterval(() => goTo(current + 1), 5000);
JavaScript burada yalnızca transform değerini değiştirir. Geçiş CSS tarafından yürütülür. will-change: transform tarayıcıya bu öğenin taşınacağını önceden bildirir; ancak her öğeye eklemek bellek maliyeti yaratır, yalnızca geçiş yapan elemana verilmelidir.
Görünmeyen slaytlar için display: none yerine visibility: hidden ve opacity: 0 kombinasyonu tercih edilebilir. Bu yaklaşım layout hesaplamalarını korurken render ağacından çıkarır ve geçiş sırasında CLS oluşmasını önler. Otomatik geçişi durdurmak için prefers-reduced-motion medya sorgusunu kontrol etmek de erişilebilirlik açısından önemlidir.
Preload stratejisi ve ağ önceliği
Carousel'in performans yükü büyük ölçüde ağ isteği zamanlamasından kaynaklanır. Birinci slayt preload ve fetchpriority="high" alır; ikinci slayt opsiyonel olarak preload edilebilir, çoğu durumda tarayıcı bunu zaten sıralamada öne alır; üçüncü ve sonrası loading="lazy" ile ertelenir.
JavaScript ile slayt yüklemesini kontrol etmek için Intersection Observer kullanılabilir:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target.querySelector('img[data-src]');
if (img) {
img.src = img.dataset.src;
observer.unobserve(entry.target);
}
}
});
});
document.querySelectorAll('.carousel-slide').forEach(slide => {
observer.observe(slide);
});
Bu yapı, slayt görünür alana girdiğinde görsel yüklemesini başlatır. Otomatik dönen carousel'lerde kullanıcı bazı slaytları hiç görmeyebileceğinden bu bir avantajdır: boşa harcanan bant genişliği azalır ve arka plan ağ etkinliği baskısı düşer.
Responsive görseller için srcset ve sizes nitelikleri carousel'de de geçerlidir. Masaüstü için 1200 piksel, mobil için 600 piksel genişlik ayrı dosyalarla sunulduğunda mobil kullanıcı gereksiz veri taşımaz; bu, carousel görsellerinin boyutu göz önünde alındığında önemli bir farktır.
Carousel testini doğru okumak
Lab ortamı carousel testlerinde yanıltıcı olabilir. Lighthouse gibi araçlar sayfayı yükledikten hemen sonra LCP öğesini ölçer; otomatik geçiş henüz başlamamıştır. Alan verisi (RUM) ise gerçek kullanıcı deneyimini yansıtır; burada carousel birkaç slayt döndükten sonra LCP ve CLS değerleri değişmiş olabilir.
Chrome DevTools "Performance" panelinde carousel geçişlerini kayıt altına almak mümkündür. Geçiş sırasında "Layout Shift" olayları görünüyorsa CLS sorununa işaret eder; "Long Task" blokları görünüyorsa animasyon mantığı veya kütüphane main thread'i tıkıyor demektir.
CLS'nin carousel kaynaklı olup olmadığını anlamak için LayoutShift attribution raporları incelenebilir:
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
console.log('Layout shift:', entry.value, entry.sources);
}
}
}).observe({ type: 'layout-shift', buffered: true });
Bu kod, kaydedilen her düzen kayışını ve kaynağını konsola yazar. Carousel kapsayıcısı kaynaklarda görünüyorsa sorun yerini net biçimde gösterir. INP adaylarını bulmak için benzer bir dinleyici 100 ms eşiğiyle kurulabilir; carousel düğmesi tıklamalarından kaynaklanan uzun süreler kütüphane işleme maliyetine işaret eder.
Carousel optimizasyonunun özü şuradadır: bileşen tamamen kaldırılmadan performans üzerindeki ağırlığı büyük ölçüde azaltılabilir. Birinci slayta preload, geri kalanlarına lazy loading, kaba aspect-ratio ve JavaScript kütüphanesi yerine CSS geçişi bir arada uygulandığında LCP, CLS ve INP'in hepsinde iyileşme beklenebilir.
Bir carousel'in gerçekten performansı etkileyen bir etken olup olmadığını anlamak için alan verisine bakmak gerekir. Lab puanı iyi görünebilir; gerçek kullanıcılar yavaş bağlantıda veya orta düzey cihazda sayfayı ziyaret ettiğinde tablo farklı olabilir. RUM verisi olmadan yapılan optimizasyon tahmine dayalı kalır.
Mevcut carousel kütüphanenizin bundle boyutunu ve main thread maliyetini Chrome DevTools Coverage ve Performance panelleriyle ölçmek iyi bir başlangıç noktasıdır. Kapsam dışı kod yüzdesi yüksek ve uzun görevler varsa, kütüphanenin CSS tabanlı bir yapıyla değiştirilmeye değer olduğu ortadadır.