Merhaba arkadaşlar, bugün başımı çok ağrıtan bir performans sorununu ve nasıl çözdüğümü anlatacağım. Bir projede, özellikle mobilde, sayfaların render olması çok yavaştı. Lighthouse skorları düşüktü ve "Eliminate render-blocking resources" uyarısı sürekli karşıma çıkıyordu. İşin özü, tarayıcı, tüm CSS dosyalarını indirip işlemeden sayfayı göstermiyordu. Bu sorunu çözmek için CSS'yi kritik ve kritik olmayan diye ikiye ayırıp farklı yükleme stratejileri uyguladım.
Sorunun Kökeni: Render Bloklama
Tarayıcı, bir HTML sayfasını yüklerken, `<head>` içindeki her bir `<link rel="stylesheet">` etiketini bulduğunda, o CSS dosyasını indirip ayrıştırana kadar DOM yapımızı render etmeyi durdurur. Bu, "render bloklama" olarak bilinir. 5-6 tane CSS dosyanız varsa ve her biri 100kb ise, kullanıcı beyaz bir ekrana bakmak zorunda kalır. Ben de bu durumu yaşıyordum.
Çözüm Yolu: Kritik CSS'yi Belirlemek
İlk adım, "Kritik CSS"yi belirlemekti. Kritik CSS, sayfanın ilk görüntülenen alanındaki (above-the-fold) içeriği stilleyen minimum CSS kodu demek. Yani, kullanıcının ilk kaydırmadan gördüğü her şeyin stilleri. Geri kalan her şey (hover efektleri, footer stilleri, modal pencereler vs.) "kritik olmayan CSS" oluyor.
Bu ayrımı yapmak için manuel olarak inceleyebilirsiniz ya da Penthouse, Critical gibi otomatik araçlar kullanabilirsiniz. Ben manuel bir yaklaşımı tercih ettim çünkü proje çok büyük değildi.
Uygulama: Inline ve Defer Etme Stratejisi
Kritik CSS'yi belirledikten sonra, onu doğrudan HTML'nin `<head>` kısmına inline olarak yazdım. Bu, tarayıcının hemen bu stilleri işlemesini ve sayfayı render etmeye başlamasını sağlar. Kritik olmayan CSS'yi ise, sayfa render olduktan sonra asenkron olarak yüklemek için `preload` ve `onload` trick'ini kullandım.
İşte benim kullandığım en temiz çözümün HTML head kısmı:
Buradaki sihir, `rel="preload"` özelliğinde. Tarayıcıya "bu dosyayı hemen yükle, ama render'ı bloklama" der. `as="style"` ile bir stil dosyası olduğunu belirtiriz. `onload` olayı tetiklendiğinde (dosya yüklendiğinde), `rel` özniteliğini `'stylesheet'` olarak değiştiririz ve CSS etkin hale gelir. `<noscript>` etiketi ise JavaScript kapalı kullanıcılar için bir yedektir.
Sonuçlar ve Çıkarımlar
Bu değişikliği yaptıktan sonra, Lighthouse "First Contentful Paint" (FCP) ve "Largest Contentful Paint" (LCP) metriklerinde ciddi iyileşmeler gördüm. Render bloklama uyarısı kayboldu. Kullanıcılar, içeriği çok daha hızlı görmeye başladı.
Tabii ki bu yöntem, CSS'inizin iki parçaya bölünmesini ve bunların yönetilmesini gerektiriyor. Build sürecinize (Webpack, Gulp vs.) kritik CSS çıkarma işlemini entegre etmek uzun vadede daha sürdürülebilir.
Siz performans iyileştirmeleri için CSS konusunda hangi yöntemleri kullanıyorsunuz? Kritik CSS çıkarma işlemini otomatikleştiren favori bir aracınız var mı? Yorumlarda deneyimlerinizi paylaşın!
Tarayıcı, bir HTML sayfasını yüklerken, `<head>` içindeki her bir `<link rel="stylesheet">` etiketini bulduğunda, o CSS dosyasını indirip ayrıştırana kadar DOM yapımızı render etmeyi durdurur. Bu, "render bloklama" olarak bilinir. 5-6 tane CSS dosyanız varsa ve her biri 100kb ise, kullanıcı beyaz bir ekrana bakmak zorunda kalır. Ben de bu durumu yaşıyordum.
İlk adım, "Kritik CSS"yi belirlemekti. Kritik CSS, sayfanın ilk görüntülenen alanındaki (above-the-fold) içeriği stilleyen minimum CSS kodu demek. Yani, kullanıcının ilk kaydırmadan gördüğü her şeyin stilleri. Geri kalan her şey (hover efektleri, footer stilleri, modal pencereler vs.) "kritik olmayan CSS" oluyor.
Bu ayrımı yapmak için manuel olarak inceleyebilirsiniz ya da Penthouse, Critical gibi otomatik araçlar kullanabilirsiniz. Ben manuel bir yaklaşımı tercih ettim çünkü proje çok büyük değildi.
Kritik CSS'yi belirledikten sonra, onu doğrudan HTML'nin `<head>` kısmına inline olarak yazdım. Bu, tarayıcının hemen bu stilleri işlemesini ve sayfayı render etmeye başlamasını sağlar. Kritik olmayan CSS'yi ise, sayfa render olduktan sonra asenkron olarak yüklemek için `preload` ve `onload` trick'ini kullandım.
İşte benim kullandığım en temiz çözümün HTML head kısmı:
HTML:
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Performans Optimizasyonu</title>
<!-- KRİTİK CSS: Inline olarak eklenir -->
<style>
/ Above-the-fold stilleri buraya /
body { font-family: sans-serif; margin: 0; }
.header { background: #2c3e50; color: white; padding: 1rem; }
.hero { padding: 4rem 2rem; text-align: center; }
/ ... diğer kritik kurallar ... /
</style>
<!-- KRİTİK OLMAYAN CSS: Asenkron yüklenir -->
<link rel="preload" href="/styles/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/non-critical.css"></noscript>
</head>
<body>
<!-- Sayfa içeriği -->
</body>
</html>
Buradaki sihir, `rel="preload"` özelliğinde. Tarayıcıya "bu dosyayı hemen yükle, ama render'ı bloklama" der. `as="style"` ile bir stil dosyası olduğunu belirtiriz. `onload` olayı tetiklendiğinde (dosya yüklendiğinde), `rel` özniteliğini `'stylesheet'` olarak değiştiririz ve CSS etkin hale gelir. `<noscript>` etiketi ise JavaScript kapalı kullanıcılar için bir yedektir.
Bu değişikliği yaptıktan sonra, Lighthouse "First Contentful Paint" (FCP) ve "Largest Contentful Paint" (LCP) metriklerinde ciddi iyileşmeler gördüm. Render bloklama uyarısı kayboldu. Kullanıcılar, içeriği çok daha hızlı görmeye başladı.
Tabii ki bu yöntem, CSS'inizin iki parçaya bölünmesini ve bunların yönetilmesini gerektiriyor. Build sürecinize (Webpack, Gulp vs.) kritik CSS çıkarma işlemini entegre etmek uzun vadede daha sürdürülebilir.
Siz performans iyileştirmeleri için CSS konusunda hangi yöntemleri kullanıyorsunuz? Kritik CSS çıkarma işlemini otomatikleştiren favori bir aracınız var mı? Yorumlarda deneyimlerinizi paylaşın!