Lighthouse'un Minimize Critical Request Depth uyarısı, zincirleme kaynak bağımlılıklarının LCP'yi nasıl geciktirdiğini gösterir. Preload ve inline stratejileriyle zinciri kısaltmak, keşif gecikmesini azaltır ve sayfa boyamasını hızlandırır.
Kritik İstek Zinciri Nedir ve Nasıl Kısaltılır?
Tarayıcı bir sayfayı yüklemeye başladığında, her kaynağı aynı anda çekemez. HTML'yi alır, içindeki bağımlılıkları keşfeder, onları alır; o kaynakların içinde başka bağımlılıklar varsa onları da bekler. Bu sıralı bekleme sürecine kritik istek zinciri (critical request chain) denir ve her halka, sayfanın görünür hale gelmesini bir adım daha geciktirir.
Lighthouse, bu durumu "Minimize Critical Request Depth" başlığıyla raporlar. Rapor, yalnızca kaç kaynak yüklendiğini değil, bu kaynakların birbirine nasıl bağımlı olduğunu ve zincirin kaç katman derinliğe ulaştığını gösterir. Derinlik arttıkça LCP (Largest Contentful Paint) gecikmesi de artar, çünkü tarayıcı son kaynağa ulaşmadan boyamayı tamamlayamaz.
Zinciri tamamen ortadan kaldırmak her zaman mümkün değildir. Ama iki halkalı bir zinciri tek halkaya indirmek, ya da dört katmanlı bir bağımlılığı iki katmana düşürmek, ölçülebilir bir kazanım sağlar. Preload ve inline stratejileri bu iş için kullanılır; ancak ikisi de kötü uygulandığında yarardan çok zarar verir.
Kritik istek zinciri: sıralı bağımlılıkların anatomisi
Tarayıcı bir HTML belgesi aldığında, içindeki <link> ve <script> etiketlerini sırayla işler. Render-blocking bir CSS dosyası bulduğunda onu indirir ve ayrıştırır; o CSS içinde @font-face kuralları varsa fontları da indirir. CSS tamamen alınmadan fontlar keşfedilemez, fontlar alınmadan metin boyama gerçekleşemez.
Bu bağımlılık zincirinin her halkası, bir ağ isteğinin tamamlanmasını beklemek demektir. Tek katmanlı bir zincirde tarayıcı HTML'yi alır ve CSS'i hemen keşfeder; iki katmanlı bir zincirde önce CSS, ardından CSS'in tetiklediği başka bir kaynak gelir. Katman sayısı arttıkça her katmanın round-trip süresi de toplam gecikmeye eklenir.
Somut bir örnek: Ana CSS dosyası 50 ms'de geliyorsa, içindeki @import ile çağrılan ikinci stil dosyası 40 ms'de geliyorsa ve bu dosya da bir font tanımı içeriyorsa, font 60 ms'de tamamlanır. Toplam bekleme 150 ms'dir; bu süre sıralı olduğundan başka işlemler bu 150 ms'yi dolduramaz. Tarayıcı boyama için bu üç kaynağın bitmesini bekler.
Paralel yüklemeyle karıştırmamak gerekir. Tarayıcı aynı anda birden fazla kaynak indirebilir; ancak bir kaynağın varlığının başka bir kaynaktan öğrenilmesi gerekiyorsa, o kaynak keşfedilene kadar paralel indirme başlayamaz. Zincirdeki gecikme, indirme kapasitesinden değil keşif gecikmesinden kaynaklanır.
Lighthouse uyarısını doğru okumak
Lighthouse'un "Minimize Critical Request Depth" denetimi, yalnızca render-blocking kaynakları değil, kritik oluşturma yolunda (critical rendering path) yer alan ve sıralı bağımlılık içeren tüm kaynakları raporlar. Sonuç ağacında her düğüm bir kaynağı, girinti derinliği ise o kaynağın kaçıncı halkada bulunduğunu gösterir.
Raporda üç değer öne çıkar: toplam zincir sayısı, maksimum derinlik ve kritik yoldaki toplam boyut. Bunların tümü önemlidir; fakat gecikme açısından maksimum derinlik en fazla ağırlık taşır. Beş zinciri olan ama hepsinin derinliği 1 olan bir sayfa, tek zinciri olup derinliği 4 olan bir sayfadan genellikle daha iyi performans gösterir.
Uyarı, her durumda acil eylem gerektirmez. Yalnızca iki kaynak içeren ve derinliği 2 olan bir zincir, performans bütçenizin içindeyse kabul edilebilir. Lighthouse puanı 90'ın üzerinde olan bir sayfada bu uyarıyı görmek normaldir; çünkü denetim, puanı değil yapısal riski raporlar. Müdahale kararı için LCP değerinize ve alan verilerinize bakın: LCP 2.5 saniyenin altındaysa zincir kısaltması öncelikli olmayabilir.
Yanıltıcı durumlar da vardır. Bazı üçüncü taraf scriptler kendi içlerinde zincirleme yüklemeler yaratır ve Lighthouse bunları da raporlayabilir. Bu kaynaklar üzerinde doğrudan kontrolünüz olmadığından, raporun hangi kaynaklara işaret ettiğini dikkatle inceleyin. Kendi kontrolünüzdeki kaynaklara odaklanmak, geliştirme süresini daha verimli kullanmanızı sağlar.
Zincir derinliği LCP'yi neden doğrudan etkiler?
LCP, sayfadaki en büyük görünür öğenin boyandığı anı ölçer. Bu öğe çoğunlukla bir hero görseli, büyük bir başlık metni ya da öne çıkan bir bölümdür. Boyamanın gerçekleşebilmesi için o öğeyi oluşturan kaynağın - görselin ya da metnin bağlı olduğu fontun - indirilmiş olması gerekir.
Zincirleme bağımlılık LCP'yi iki yoldan geciktirir. Birincisi, kritik kaynağın keşfi gecikir: tarayıcı LCP görselinin URL'sini HTML'den değil, CSS'ten ya da JavaScript'ten öğreniyorsa, bu kaynaklar alınmadan görsel indirmesi başlayamaz. İkincisi, render-blocking süreç uzar; ana iş parçacığı (main thread) sıradaki kaynağı beklerken başka boyama görevlerini de erteleyebilir.
Sayılarla ifade etmek gerekirse: Ağ gecikmesi 50 ms, CSS 80 ms'de geliyorsa ve CSS içinde keşfedilen bir font 70 ms'de tamamlanıyorsa, font öncesinde hiçbir metin boyanamazsa LCP en az 200 ms gecikir. Aynı font ilk HTML isteğiyle birlikte preload edilseydi CSS ile paralel indirilirdi ve sıralı bekleme 70 ms'ye inerdi.
Hero görseli için aynı durum geçerlidir. Görsel CSS background-image ile yükleniyor ve CSS render-blocking ise, görsel indirmesi yalnızca CSS bittikten sonra başlar. HTML içinde <img> etiketi kullanılmış olsaydı tarayıcı preload taraması (preload scanner) sayesinde görseli CSS ile aynı anda keşfedebilirdi.
Kısa cümle: keşif gecikmesi, indirme süresinden pahalıdır. Çünkü indirme paralel çalışabilir; keşif ise sıralıdır ve her sıralı adım tüm sonraki kaynakları bekletir, render tamamlanana kadar bu bekleme zinciri devam eder.
Preload: zinciri kıran değil, öne çeken strateji
Preload (<link rel="preload">), tarayıcıya bir kaynağın erken indirilmesi gerektiğini söyler. Keşif gecikmesini ortadan kaldırır; kaynak, onu tetikleyen CSS ya da JavaScript alınmadan önce indirilmeye başlar. Preload'un kritik istek zincirini kırmadığını anlamak önemlidir: zincirdeki sırayı değiştirirsiniz, kaynağı zincirin dışına çıkarırsınız.
LCP öğeniz bir hero görseli ve bu görsel CSS background-image olarak tanımlıysa, HTML <head> bölümüne şu satırı ekleyin:
<link rel="preload" href="/gorsel/hero.webp" as="image" fetchpriority="high">
Bu satır, tarayıcıya sayfanın ilk isteğiyle birlikte hero görselini indirmesini söyler. CSS henüz alınmamış olsa bile görsel arka planda indirilir. CSS geldiğinde görsel hazırdır, boyama hemen gerçekleşir.
Font için kullanım benzerdir. CSS içindeki @font-face ile yüklenen kritik bir font varsa:
<link rel="preload" href="/fonts/arayuz.woff2" as="font" type="font/woff2" crossorigin>
Burada crossorigin özniteliği zorunludur. Fontlar CORS politikasına tabidir; bu öznitelik olmadan tarayıcı fontu iki kez indirir: biri preload için, biri gerçek kullanım için. İki ayrı indirme, kazancın tamamını sıfırlar.
Preload'un ters etki yarattığı durumlar da vardır. Sayfa yüklemesinde kullanılmayan bir kaynağı preload etmek, bant genişliğini çalar ve gerçekten kritik kaynakların indirilmesini yavaşlatır. Zaten HTML'den keşfedilebilen bir görseli - yani <img> etiketiyle yüklenen bir kaynağı - preload etmek genellikle gereksizdir; tarayıcı preload scanner bunu zaten erken yakalar. Preload, her kaynak için değil yalnızca geç keşfedilen kritik kaynaklar için tercih edilmelidir.
Birden fazla kaynağı preload etmek de dikkat ister. Üç farklı fontu aynı anda preload ederseniz, ilk render için gereken kaynak sayısını artırır ve ilk boyamayı geciktirebilirsiniz. Preload listesini en fazla iki veya üç kaynak ile sınırlı tutmak, çoğu durumda daha güvenli bir yaklaşımdır.
Inline etmek: ne zaman kazanç, ne zaman yük?
Inline etmek, harici kaynağı ağ isteği gerektirmeden doğrudan HTML veya CSS içine gömmek demektir. Kritik CSS'i <style> etiketi içinde HTML'ye dahil etmek, render-blocking isteği tamamen ortadan kaldırır. Tarayıcı HTML'yi alır, stilini içinde bulur, boyamayı başlatır; ayrı bir CSS dosyası için beklemesi gerekmez.
Kritik CSS inline stratejisi şöyle kurulur. İlk ekranda görünecek öğelerin stilleri HTML <head> içine inline edilir; geri kalanı asenkron yüklenir:
<style>
body { margin: 0; font-family: 'Arayuz', sans-serif; }
.hero { background: #1a1a2e; min-height: 60vh; }
</style>
<link rel="stylesheet" href="/css/tum-stiller.css" media="print" onload="this.media='all'">
Bu yapıda ana CSS dosyası başlangıçta yalnızca yazdırma için yüklenir ve sayfa boyandıktan sonra all olarak güncellenir. Kullanıcı bu geçişi görmez; render-blocking isteği ortadan kalkmıştır.
Inline etmenin sınırı vardır. Kritik CSS şişerse HTML boyutu büyür ve ilk HTTP yanıtı yavaşlar; kazanç geri alınır. Eski pratikte 14 KB ilk congestion window eşiği olarak anılırdı; güncel ağlarda bu pencere daha geniş olsa da kritik CSS'i HTML'e gömmek yanıtı şişirir. Inline edilecek içeriği görünür alanın gerçekten ihtiyaç duyduğu kurallarla sınırlamak, net bir avantaj sağlar.
Küçük SVG ikonları doğrudan HTML içine yerleştirmek de bir inline stratejisidir. Harici bir SVG dosyası ek bir istek gerektirir; inline edilmesi bu isteği sıfırlar. Ama aynı ikonu birden fazla sayfada kullanıyorsanız, harici dosya tarayıcı önbelleğinden gelir ve tekrar indirilmez. Tek sayfalık kullanımda inline kazançlı, çok sayfalı kullanımda önbellekten gelen harici dosya daha verimli olabilir.
Fontları inline etmek ise genellikle önerilmez. WOFF2 dosyaları base64 kodlandığında boyutları yaklaşık üçte bir büyür. 40 KB'lık bir fontun base64 versiyonu yaklaşık 54 KB olur ve bu yük her sayfada HTML içinde taşınır. Preload ile paralel indirme sağlamak, font için inline etmeye kıyasla genellikle daha dengeli bir çözümdür.
Değişiklikten sonra zinciri nasıl doğrularsınız?
Preload veya inline değişikliği yaptıktan sonra etkiyi doğrulamak, değişikliği yapmak kadar önemlidir. Chrome DevTools'taki Network paneli bu iş için yeterlidir.
Network panelini açın, sayfayı yenileyin ve "Initiator" sütununa bakın. Bir kaynağın başlatıcısı başka bir kaynak gösteriyorsa, aralarında bir bağımlılık var demektir. Şelale (waterfall) görünümünde kritik kaynakların başlangıç noktası, diğer kaynaklar bitmeden önce mi başlıyor? Hero görselinizin çubuğu HTML isteğiyle yakın bir konumda başlıyorsa preload işe yarıyor demektir.
Coverage sekmesini açarak inline ettiğiniz kritik CSS'in gerçekten ilk ekranda kullanılıp kullanılmadığını da kontrol edebilirsiniz. Inline CSS'in büyük bölümü kırmızı - yani kullanılmamış - gösteriliyorsa, kritik olmayan stiller de inline edilmiş demektir; bu hem boyutu şişirir hem de ilk render kazancını azaltır.
Lighthouse denetimini tekrar çalıştırdığınızda "Minimize Critical Request Depth" uyarısının durumunu inceleyin. Zincir derinliği düştüyse değişiklik etkili olmuş demektir. Puanda büyük bir değişiklik olmayabilir; çünkü bu denetim Lighthouse toplam puanına sınırlı ağırlıkla katkıda bulunur. LCP değerinin düştüğünü görmek daha doğrudan bir göstergedir.
Alan verilerini gözlemlemek için Chrome User Experience Report veya Search Console'daki Core Web Vitals raporu kullanılabilir. Değişikliğin yayına girdiği tarihi not alın; bir ila iki hafta sonra LCP dağılımının değişip değişmediğini kontrol edin. Laboratuvar ölçümleri hemen yanıt verir; alan verileri ise gerçek kullanıcı etkisini gösterir ve biraz daha sabır gerektirir.
Kritik istek zinciri, sayfanın yapısına gömülü bir gecikme mekanizmasıdır. CSS'in fontu çağırması, @import'un başka bir stil dosyasını tetiklemesi gibi dolaylı bağımlılıklar çoğunlukla kasıtsız oluşur ve fark edilmesi zaman alır.
Preload ve inline, bu soruna karşı en doğrudan araçlardır; fakat ikisi de aşırı kullanıldığında bant genişliğini gereksiz tüketir. En sağlıklı yaklaşım, hangi kaynağın gerçekten kritik render yolunda olduğunu belirlemek, yalnızca o kaynak için müdahale etmek ve her değişikliği ölçmektir.
Lighthouse puanı değişmese bile, Network şelale grafiğinde zincirin kısaldığını görmek somut bir gelişmenin işaretidir. LCP ve FCP metriklerindeki iyileşme alan verileriyle de teyit ediliyorsa, doğru yönde ilerliyorsunuz demektir.