İçeriğe geç
CSS

CSS Scroll-Driven Animations Rehberi

Tarık Tunç
CSS Scroll-Driven Animations Rehberi

CSS Scroll-Driven Animations Rehberi

CSS Scroll-Driven Animations, web sayfalarında scroll pozisyonuna bağlı animasyonları JavaScript kullanmadan saf CSS ile oluşturmanızı sağlayan devrim niteliğinde bir özelliktir. Daha önce Intersection Observer ve scroll event listener'ları gerektiren parallax efektleri, progress bar'lar ve scroll-triggered animasyonlar artık performanslı şekilde CSS ile yapılabilir. Bu rehberde scroll timeline'ların kullanımını detaylıca inceleyeceğiz.

1. Scroll Timeline Temelleri

Scroll-driven animasyonlar iki temel timeline türü sunar: scroll() bir scroll container'ın toplam scroll ilerlemesini takip eder, view() ise bir elemanın viewport içindeki görünürlüğünü takip eder. Her ikisi de mevcut CSS @keyframes animasyonlarını kullanır.

/* Scroll Progress Bar — Sayfa ilerlemesi */
.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: #3b82f6;
  transform-origin: left;
  transform: scaleX(0);

  /* Scroll timeline bağlama */
  animation: grow-progress linear;
  animation-timeline: scroll(); /* Varsayılan: nearest scroll container */
}

@keyframes grow-progress {
  to {
    transform: scaleX(1);
  }
}

/* Scroll Container belirtme */
.sidebar-progress {
  animation: grow-progress linear;
  animation-timeline: scroll(nearest block);
  /* nearest: en yakın scroll container */
  /* root: document scroll */
  /* self: elemanın kendi scroll'u */
  /* block: dikey, inline: yatay */
}

/* Named Scroll Timeline */
.scroll-container {
  scroll-timeline-name: --main-scroll;
  scroll-timeline-axis: block;
  overflow-y: auto;
  height: 100vh;
}

.animated-element {
  animation: fadeIn linear;
  animation-timeline: --main-scroll;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
Bilgi: Scroll-driven animasyonlarda animation-duration belirtmenize gerek yoktur. Süre, scroll ilerlemesiyle otomatik olarak eşlenir. linear timing function genellikle en doğal sonucu verir.

2. View Timeline ile Scroll-Triggered Animasyonlar

view() timeline'ı, bir elemanın scroll container'ın viewport'unda görünür olup olmadığını takip eder. Bu, Intersection Observer'ın CSS karşılığıdır ve scroll-reveal animasyonları için idealdir.

/* Scroll Reveal — Görünüme girince anime et */
.reveal-card {
  opacity: 0;
  transform: translateY(50px);

  animation: reveal linear both;
  animation-timeline: view(); /* Elemanın viewport görünürlüğü */
  animation-range: entry 0% entry 100%;
  /* entry: eleman viewport'a girmeye başladığında
     0% → elemanın üst kenarı viewport alt kenarında
     100% → eleman tamamen viewport içinde */
}

@keyframes reveal {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Farklı animation-range değerleri */
.fade-through {
  animation: fadeThrough linear both;
  animation-timeline: view();
  animation-range: cover 0% cover 100%;
  /* cover: viewport'u geçerken baştan sona */
}

@keyframes fadeThrough {
  0%   { opacity: 0; transform: scale(0.8); }
  30%  { opacity: 1; transform: scale(1); }
  70%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.8); }
}

/* Yatay Parallax Efekti */
.parallax-text {
  animation: slideRight linear both;
  animation-timeline: view();
  animation-range: contain 0% contain 100%;
}

@keyframes slideRight {
  from { transform: translateX(-100px); }
  to   { transform: translateX(100px); }
}

/* Staggered Reveal — Sıralı görünüm */
.card:nth-child(1) { animation-range: entry 0% entry 80%; }
.card:nth-child(2) { animation-range: entry 10% entry 90%; }
.card:nth-child(3) { animation-range: entry 20% entry 100%; }

3. Parallax ve İleri Seviye Efektler

Scroll-driven animasyonlar, parallax efektleri, sticky header geçişleri ve karmaşık scroll deneyimleri oluşturmak için mükemmeldir. JavaScript'e kıyasla çok daha performanslıdır çünkü compositor thread'de çalışır.

/* Parallax Hero Section */
.hero {
  height: 100vh;
  position: relative;
  overflow: hidden;
}

.hero-background {
  position: absolute;
  inset: -20%;
  animation: parallax-bg linear;
  animation-timeline: scroll();
}

@keyframes parallax-bg {
  to {
    transform: translateY(30%);
  }
}

.hero-content {
  position: relative;
  z-index: 1;
  animation: hero-fade linear both;
  animation-timeline: scroll();
  animation-range: 0% 30%;
}

@keyframes hero-fade {
  to {
    opacity: 0;
    transform: translateY(-50px);
  }
}

/* Sticky Header — Scroll'da küçülen header */
.header {
  position: sticky;
  top: 0;
  z-index: 100;
  animation: shrink-header linear both;
  animation-timeline: scroll();
  animation-range: 0px 200px;
}

@keyframes shrink-header {
  from {
    padding-block: 2rem;
    background: transparent;
    backdrop-filter: none;
  }
  to {
    padding-block: 0.5rem;
    background: rgba(255, 255, 255, 0.9);
    backdrop-filter: blur(10px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }
}

/* Horizontal Scroll Section */
.horizontal-section {
  overflow-x: auto;
  scroll-timeline-name: --horizontal;
  scroll-timeline-axis: inline;
}

.horizontal-section .item {
  animation: slideUp linear both;
  animation-timeline: --horizontal;
}

@keyframes slideUp {
  from { transform: translateY(100px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}
İpucu: Chrome DevTools'un "Animations" panelinde scroll-driven animasyonları debug edebilirsiniz. Timeline'ı scrub ederek her karedeki durumu görebilirsiniz. Firefox'ta da benzer araçlar mevcuttur.

4. Performans ve Erişilebilirlik

Scroll-driven animasyonlar compositor thread'de çalıştığı için main thread'i bloklamaz. Ancak doğru kullanım ve erişilebilirlik kurallarına dikkat etmek gerekir.

/* Performanslı kullanım — sadece compositor özellikleri */
@keyframes optimized-reveal {
  from {
    opacity: 0;
    transform: translateY(30px);
    /* opacity ve transform GPU'da çalışır */
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* KAÇININ — Layout tetikleyen özellikler */
@keyframes bad-animation {
  from { height: 0; margin-top: 50px; } /* Layout recalculation */
  to   { height: auto; margin-top: 0; }
}

/* Erişilebilirlik — Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .reveal-card {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .parallax-bg {
    animation: none;
  }

  .progress-bar {
    /* Progress bar gibi bilgilendirici animasyonlar kalabilir */
    /* Sadece dekoratif animasyonları devre dışı bırakın */
  }
}

/* Feature detection */
@supports (animation-timeline: scroll()) {
  .scroll-animated {
    animation: reveal linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 100%;
  }
}

/* Fallback — Scroll-driven desteklenmiyorsa */
@supports not (animation-timeline: scroll()) {
  .scroll-animated {
    opacity: 1;
    transform: none;
  }
}
Uyarı: Scroll-driven animations Chrome 115+ ve Edge 115+ suresinde desteklenmektedir. Firefox ve Safari desteği henuz tamamlanmamistir. Produksiyon'da @supports ile feature detection kullanin ve desteklenmeyen tarayicilar icin fallback saglayin.

Sonuç

CSS Scroll-Driven Animations, scroll bazlı etkileşimleri JavaScript'ten CSS'e taşıyarak hem geliştirici deneyimini hem de performansı önemli ölçüde iyileştirmektedir. scroll() ile genel ilerleme, view() ile eleman görünürlüğü takip edilir. Parallax efektleri, progress bar'lar, scroll-reveal animasyonları ve sticky header geçişleri artık saf CSS ile yapılabilir. Erişilebilirlik için prefers-reduced-motion kontrolü, tarayıcı uyumluluğu için @supports kontrolü eklemeyi unutmayın.

Kaynaklar

İlgili Yazılar