Critical Rendering Path: Tarayıcı Render Süreci

Critical Rendering Path: Tarayıcı Render Süreci
Critical Rendering Path (CRP), tarayıcının HTML, CSS ve JavaScript'i ekrandaki piksellere dönüştürdüğü adımlar bütünüdür. Bu süreci anlamak, web performans optimizasyonunun temelidir. Tarayıcının her adımda ne yaptığını bilmek, darboğazları tespit etmenizi ve ilk render süresini minimize etmenizi sağlar. Bu rehberde CRP'nin her aşamasını inceleyecek ve optimizasyon stratejilerini kod örnekleri ile göstereceğiz.
Render Süreci Adımları
Tarayıcı bir sayfayı render ederken şu adımları takip eder:
- HTML Parsing → DOM Oluşturma: HTML byte'ları tokenize edilir ve DOM (Document Object Model) ağacı oluşturulur.
- CSS Parsing → CSSOM Oluşturma: CSS dosyaları parse edilerek CSSOM (CSS Object Model) ağacı oluşturulur.
- JavaScript Çalıştırma: Script'ler çalıştırılır, DOM ve CSSOM değiştirilebilir.
- Render Tree Oluşturma: DOM ve CSSOM birleştirilerek sadece görünür öğeleri içeren render tree oluşturulur.
- Layout (Reflow): Her öğenin sayfa üzerindeki konum ve boyutu hesaplanır.
- Paint: Piksel bilgileri oluşturulur (renk, gölge, metin, görsel vb.).
- Composite: Katmanlar birleştirilerek ekrana çizilir.
Render-Blocking Kaynaklar
CSS ve senkron JavaScript, render sürecini bloke eden en yaygın kaynaklardır. Bu kaynakların yönetimi, ilk render süresini doğrudan etkiler:
<!-- KÖTÜ: Tüm CSS render-blocking -->
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/css/animations.css">
<link rel="stylesheet" href="/css/print.css">
<!-- İYİ: Critical CSS inline, geri kalan async yükle -->
<style>
/* Critical CSS - above-the-fold için gerekli minimum stiller */
*,*::before,*::after{box-sizing:border-box}
body{margin:0;font-family:system-ui,-apple-system,sans-serif;line-height:1.6}
.header{background:#1a1a2e;color:#fff;padding:1rem 2rem}
.hero{padding:4rem 2rem;text-align:center}
.hero h1{font-size:2.5rem;margin-bottom:1rem}
</style>
<!-- Non-critical CSS async yükleme -->
<link rel="preload" href="/css/main.css" as="style"
>
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
<!-- Print CSS: media attribute ile sadece yazdırma için -->
<link rel="stylesheet" href="/css/print.css" media="print">
JavaScript Loading Stratejileri
JavaScript'in DOM parse sürecini bloke etmesini önlemek için doğru yükleme stratejisini seçmelisiniz:
<!-- Normal: HTML parsing'i durdurur, indir ve çalıştır -->
<script src="/js/app.js"></script>
<!-- async: Paralel indir, hazır olunca hemen çalıştır (parsing durur) -->
<!-- Bağımsız scriptler için: analytics, ads -->
<script async src="/js/analytics.js"></script>
<!-- defer: Paralel indir, HTML parsing bittikten sonra sırayla çalıştır -->
<!-- DOM'a bağımlı scriptler için: uygulama kodu -->
<script defer src="/js/app.js"></script>
<script defer src="/js/components.js"></script>
<!-- type="module": Otomatik defer davranışı -->
<script type="module" src="/js/app.mjs"></script>
defer ve async arasındaki kritik fark: defer scriptler HTML'deki sırayı korur ve DOMContentLoaded'dan önce çalışır. async scriptler ise indirme tamamlanır tamamlanmaz çalışır ve sıra garantisi yoktur. Uygulama kodunuz için defer tercih edin.
Critical CSS Çıkarma
Critical CSS, above-the-fold içeriği render etmek için gereken minimum CSS'tir. Bu CSS'i inline ederek ilk render için ek HTTP isteği gerekmez:
// critical CSS çıkarma - Node.js script
const critical = require('critical');
async function generateCriticalCSS() {
const result = await critical.generate({
src: 'https://example.com',
width: 1300,
height: 900,
inline: false, // Sadece critical CSS'i çıkar
target: {
css: 'critical.css',
uncritical: 'rest.css'
},
// Birden fazla viewport boyutu
dimensions: [
{ width: 375, height: 667 }, // Mobile
{ width: 768, height: 1024 }, // Tablet
{ width: 1440, height: 900 } // Desktop
]
});
console.log('Critical CSS boyutu:', result.css.length, 'bytes');
}
generateCriticalCSS();
Layout Thrashing'den Kaçınma
Layout thrashing, JavaScript'in DOM'u okuyup yazma işlemlerini karışık sırada yapması sonucu tarayıcının gereksiz yere tekrar tekrar layout hesaplaması yapmasıdır:
// KÖTÜ: Layout thrashing - her iterasyonda forced reflow
function badLayout(elements) {
elements.forEach(el => {
// Okuma → Layout tetikler
const height = el.offsetHeight;
// Yazma → Layout'u invalidate eder
el.style.height = (height * 2) + 'px';
// Sonraki okuma tekrar layout tetikler!
});
}
// İYİ: Batch read, sonra batch write
function goodLayout(elements) {
// Önce tüm okumaları yap
const heights = elements.map(el => el.offsetHeight);
// Sonra tüm yazmaları yap
elements.forEach((el, i) => {
el.style.height = (heights[i] * 2) + 'px';
});
}
// EN İYİ: requestAnimationFrame ile yazma işlemlerini bir sonraki frame'e taşı
function bestLayout(elements) {
const heights = elements.map(el => el.offsetHeight);
requestAnimationFrame(() => {
elements.forEach((el, i) => {
el.style.height = (heights[i] * 2) + 'px';
});
});
}
offsetHeight, offsetWidth, getBoundingClientRect(), scrollTop gibi özellikler forced reflow tetikler. Bu özellikler DOM yazma işlemlerinden sonra okunursa tarayıcı layout'u yeniden hesaplamak zorunda kalır. Okuma ve yazma işlemlerini her zaman gruplayın.
Composite-Only Animasyonlar
Sadece transform ve opacity özellikleri GPU tarafından compositing aşamasında işlenir ve layout/paint tetiklemez. Performanslı animasyonlar için bu özellikleri tercih edin:
/* KÖTÜ: Layout + Paint tetikler (her frame'de) */
.animate-bad {
transition: left 0.3s, top 0.3s, width 0.3s;
}
.animate-bad:hover {
left: 100px;
top: 50px;
width: 200px;
}
/* İYİ: Sadece composite - GPU hızlandırmalı */
.animate-good {
transition: transform 0.3s, opacity 0.3s;
will-change: transform, opacity;
}
.animate-good:hover {
transform: translate(100px, 50px) scale(1.2);
opacity: 0.8;
}
/* will-change: Tarayıcıya önceden haber ver (dikkatli kullanın) */
.card {
will-change: transform; /* Sadece animasyon olacak öğelerde */
}
.card:hover {
transform: translateY(-4px);
}
CRP Optimizasyon Kontrol Listesi
Critical Rendering Path'i optimize etmek için sistematik olarak şu adımları takip edin:
- Critical CSS'i inline edin, geri kalanı async yükleyin
- JavaScript'leri
deferveyaasyncile yükleyin - Render-blocking kaynak sayısını minimize edin
- CSS ve JS dosyalarını minify ve sıkıştırın
- Preload ile kritik kaynakların keşfini hızlandırın
- DOM boyutunu küçük tutun (1500 öğe altı hedefleyin)
- Layout thrashing'den kaçının
- Animasyonlarda transform ve opacity tercih edin
Sonuç
Critical Rendering Path'i anlamak, web performans optimizasyonunun temelidir. Tarayıcının HTML'den piksele giden yolculuğunu bilmek, darboğazları tespit etmenizi ve doğru optimizasyon stratejisini seçmenizi sağlar. Render-blocking kaynakları yönetmek, critical CSS inline etmek ve JavaScript yükleme stratejilerini doğru uygulamak, ilk render süresini dramatik şekilde azaltabilir.