Metin Gülerce | Senior Frontend Developer

CSS ile Skeleton Loader Hazirlama

24 Şubat 2025
CSS`in cascading özelliğini kullanarak tek noktadan yönetilebilen, performanslı bir skeleton loading sistemi nasıl oluşturulur? Vue.js tabanlı web uygulamalarında minimum kod ile maksimum etki sağlayan kapsayıcı CSS pattern`i ile tanışın.

CSS ile Kapsayıcı Skeleton Loading Yaklaşımı

Giriş

Modern web uygulamalarında kullanıcı deneyimini iyileştirmek için loading durumlarını yönetmek çok önemlidir. Bu makalede, Vue.js tabanlı bir projede CSS kullanarak nasıl etkili bir skeleton loading sistemi oluşturduğumuzu anlatacağım. Aslında Vue ile çok bir alaksı yok. Tüm önyüz projelerinizde sadece css kullanarak her komponent için ayrı ayrı skeleton yazma zahmetinden kurtulacaksınız.

Ayrıcana bu çalışma benim yıllardır uygulamaya çalıştığım ve adını kapsayıcı yaklaşım olarak tanımladığım yaklaşımın sizinle paylaştığım ilk örneği olacak.

Problemin Tanımı

Çok dilli bir web uygulamasında, dil değişikliği yapıldığında veya sayfa ilk yüklendiğinde çeviri verilerinin API'den gelmesini beklerken kullanıcıya boş bir ekran veya fmt keyler göstermek yerine, içeriğin yükleneceğini belirten bir gösterim yapmak istiyoruz.

Burada biz çok dilli sistem dedik ama herhangi bir veri tabanından içerik çekmeniz gerektiği yerde textleriniz ekrana tam olarak oturana kadar gösterilmemesi tercih edilmesi gereken bir durumdur.

Mantığı anladıktan sonra zaten sadece text değil diğer medya ve elementlere de uygulayabileceksiniz.

Geleneksel yaklaşımlar:

  1. Loading spinner göstermek (Tüm sayfayı kapatan loader animasyonu veya gif ile sayfayı bir süre gizli tutmak)
  2. Her component için ayrı skeleton componentler oluşturmak (Aslında en iyi yöntem olduğunu inkar edemem ki yapay zekalara konu danışıldığında ilk önerisi bu oluyor. Ancak maliyeti faydasından çok daha fazla. Projenizin genişlemesi dışınca ciddi bir development maliyeti var.)
  3. Placeholder içerikler kullanmak (Benim en mantıksız bulduğum ancak bir çok devasa projede gördüğüm bir durum bu. Kendi sisteminizden daha hızlıda olsa çoğunlukla third party bir api den place holder içerikler çekenleri gördüm. Benim gibi titiz önyüzcülerin aklına hemen aynı paradox gelmiştir :) Peki sitemizdeki içerikler genele kadar göstermek istediğimiz palceholder içeriklerin gelmesi uzun sürerse o arada ne göstericez ? )

Benim Çözümüm: Kapsayıcı CSS Yaklaşımı

Geliştirdiğimiz çözüm, CSS'in cascading (basamaklama) özelliğini kullanarak tek bir noktadan tüm metin elementlerine skeleton efekti uygulayan bir yaklaşımdır.

Temel Prensipler

  1. Tek Nokta Kontrolü: Tüm loading durumunu tek bir state ile yönetmek
  2. Minimum Kod Tekrarı: Her component için ayrı skeleton component yazmaktan kaçınmak
  3. Kolay Bakım: CSS cascade özelliği sayesinde merkezi yönetim
  4. Performans: CSS animasyonları kullanarak yüksek performans
  5. Sıfır Bağımlılık: Third party bir bağımlılık yok

Teknik Detaylar

Vue için örneklendirdim çünkü şuanda gezindiğiniz Metin Gülerce'nin kişisel web sitesi vue ile yazıldı. Kendi siteme uyguladığım kısmı size anlatacağım. Ancak mantık tüm dil ve freamworklerde uygulanabilir. Kodlardan sonra bundan tekrar bahs edicem.

1. Loading State Yönetimi

<script setup>
const isLoading = ref(true)

// API çağrısı sırasında loading durumunu yönetme
const fetchData = async () => {
  isLoading.value = true
  try {
    await getData()
  } finally {
    isLoading.value = false
  }
}
</script>

2. CSS Animasyon Tanımı

@keyframes shine {
  100% { 
    transform: translateX(100%); 
  }
}

3. Kapsayıcı CSS Sınıfı

/* Text elementleri için base stiller */
.skeleton-loading h1,
.skeleton-loading h2,
.skeleton-loading p,
.skeleton-loading span {
  position: relative;
  overflow: hidden;
  color: transparent; /* Opsiyonel */
}

/* Shine efekti için pseudo-element */
.skeleton-loading h1::before,
.skeleton-loading h2::before,
.skeleton-loading p::before,
.skeleton-loading span::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.05),
    transparent
  );
  transform: translateX(-100%);
  animation: shine 1.5s infinite;
}

4. Template Uygulaması

App.vue dosyası gibi tepede bir dosyada tüm layoutları kapsanayan bir div içide verebilirsiniz bu classı veya doğrudan javaScript ile body tagına ekleyip çıkartbilirsiniz. Ama projeyi tam olarak bilmeden vetanımadan doğrudan kapsayıcı yaklaşım ile kod yazmanızı çok tavsiye etmem.
<template>
  <div :class="{ 'skeleton-loading': isLoading }">
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
  </div>
</template>

Evet kodları okudğunuzda büyük oranda mantığı kurmuşsunuzdur ama yinede diğer diller ve freamworkler içinde özetleyeyim. Şayet react ile skeleton yazacaksanız veya php ile skeleton yazacaksanız mantık hep aynı.

Öncelikle içeriklerin ekrana gelişini takpi edebiliyor olmanız gerekemekte. Projenizde içerik yönetimi dağınık halde ise yine uygulayabliirsiniz ama merkezileştirmeniz avantaj sağlar. %100 Merkezileştiremezseniz de helper dosyalarından yararlanıp kod tekrarnını azaltın.

Devam ediyorum İçerikleri çektiğiniz yada çoklu dil desteği için işlediğiniz fonksiyonu try & catch bloguna alın. Fonksiyon başlarken ve finaly kısmında c lassı kontrol edeceğimiz değişkeni manipüle edeceğiz.

Class'ı tanımlarken sitenizde genel olarak kullandığınız ve ileride kullanabileceğiniz tüm html text taglarını düşünüp ekleyin. Sakın .loader > * {...} gibi bir tanım eklemeyin :) Sadece text taglarını ve classılarını kapsayın. Mantık bu kadar basit.

Avantajlar

  1. Düşük Bakım Maliyeti:
    • Tek bir CSS sınıfı ile tüm uygulamadaki loading durumlarını yönetebiliyoruz
    • Merkezi kontrol sayesinde değişiklikler tek noktadan yapılabilir
    • Component bazlı skeleton tanımlamalarına gerek kalmaz
  2. Performans:
    • Ekstra DOM elementleri oluşturmuyoruz
    • CSS animasyonları GPU tarafından işleniyor
    • Minimum JavaScript kullanımı
    • Gereksiz re-render'ların önüne geçiliyor
  3. Geliştirici Deneyimi:
    • Component'lerde ekstra kod yazmaya gerek yok
    • Loading durumları için ayrı component'ler oluşturmaya gerek yok
    • Kolay debug ve güncelleme imkanı
    • CSS cascade sayesinde otomatik stil uygulaması
  4. Esneklik:
    • Farklı elementler için farklı efektler tanımlayabilme
    • Animasyon türünü ve süresini kolayca değiştirebilme
    • Responsive tasarıma uygun yapı

Dezavantajlar ve Dikkat Edilmesi Gerekenler

  1. Browser Desteği:
    • Modern CSS özellikleri kullanıldığında eski tarayıcılarda sorun yaşanabilir (Ki biz kullanmadık. Çok da gerek yok bu özelliklere dümdüz arkaplan verip textleri gizleyip kullanın )
    • Fallback mekanizmaları düşünülmeli (Dikkat edilmesi gereken)
    • CSS @supports kullanılarak alternatif stiller tanımlanabilir ama bu durumda karmaşa artacaktır.
  2. Performans Optimizasyonu:
    • Çok sayıda element için pseudo-element oluşturulacağından, performans optimizasyonları önemli
    • will-change ve backface-visibility gibi özellikleri kullanmak gerekebilir
    • Gereksiz yere fazla element seçilmemeli
  3. Özelleştirme Limitleri:
    • Her element için farklı boyut ve şekillerde skeleton gösterimi gerektiğinde bu yaklaşım yetersiz kalabilir
    • Kompleks layout'lar için ek çözümler gerekebilir

En İyi Kullanım Örnekleri

  1. Çok Dilli Uygulamalar:
    • Dil değişikliklerinde içerik yüklenene kadar skeleton gösterimi
    • API'den gelen çeviri verilerinin bekleme durumu
    • Yerel dil dosyalarının yüklenme süreci
  2. İçerik Ağırlıklı Sayfalar:
    • Blog posts
    • Dokümantasyon sayfaları
    • Profil sayfaları
    • Ürün detay sayfaları
  3. Dinamik İçerik:
    • API'den gelen verilerin gösterildiği listeler
    • Filtrelenebilir içerikler
    • Arama sonuçları
    • Sonsuz scroll yapıları

Uygulama İpuçları

  1. Performans Optimizasyonu:
    .skeleton-loading {
      /* GPU hızlandırması için */
      will-change: transform;
      /* Gereksiz render'ları önlemek için */
      backface-visibility: hidden;
    }
    
  2. Fallback Mekanizması:
@supports not (inset: 0) {
  .skeleton-loading::before {
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
}
  1. Accessibility:
<template>
  <div 
    :class="{ 'skeleton-loading': isLoading }"
    :aria-busy="isLoading"
    role="alert"
    aria-live="polite"
  >
    <!-- içerik -->
  </div>
</template>

Sonuç

Bu yaklaşım, özellikle içerik ağırlıklı ve çok dilli uygulamalarda loading durumlarını yönetmek için etkili bir çözüm sunuyor. Minimum kod ile maksimum etki sağlayan bu pattern, modern web uygulamalarında kullanıcı deneyimini iyileştirmek için ideal bir seçenek.

CSS'in cascading özelliğini kullanarak geliştirdiğimiz bu çözüm, geleneksel yaklaşımlara göre daha az kod, daha kolay bakım ve daha iyi performans sunuyor. Özellikle büyük ölçekli uygulamalarda, loading durumlarının merkezi yönetimi için güçlü bir alternatif oluşturuyor.

Ayrıca şuanda ziyaret ettiğiniz MetinGülerce.com sistesinde de blog kısmı hariç bu bahs ettiğim yöntemler ile skeleton uygulanmaktadır. Blog kısmında olmama sebebi blog kısmını çok dilli yapmamış olmam ve içerikleri markdown olarak sunmamdır.

Kaynaklar

© 2025 Metin Gülerce. rights_reserved