CSS Scroll-Driven Animasyonlar: scroll() ve view() Nasıl Çalışır
Sayfa kaydırıldıkça beliren bir kart ya da yukarıda dolan bir ilerleme çubuğu için yıllarca JavaScript yazdık. Chromium 115'ten beri bu işlerin ikisi de saf CSS ile yapılabiliyor. Mantık, bildiğiniz keyframe mantığının aynısı; değişen tek şey animasyonu neyin ilerlettiği.
Animasyonu ilerleten şey saat olmak zorunda değil
Normal bir CSS animasyonunda tarayıcı bir zaman çizelgesi tutar. animation: fadeIn 1s yazdığınızda o çizelge saniyelerle ilerler, keyframe'ler o ilerlemeye göre hesaplanır.
Scroll-driven animasyonlarda tek yaptığınız, bu çizelgeyi başka bir şeye bağlamak. animation-timeline özelliği tarayıcıya "zamanı saatten değil, kaydırmadan al" der. Kaydırma yüzde 40'taysa animasyon da yüzde 40'ındadır; yukarı kaydırırsanız animasyon geri sarar. Keyframe'lerinizi değiştirmeniz gerekmez, sadece çizelgenin kaynağı değişir.
İki kaynak var: kaydırma kutusunun kendi ilerlemesi ve tek bir ögenin ekranda görünme süreci.
scroll(): kaydırma kutusunun ilerlemesi
Klasik örneği okuma çubuğu. Sayfanın en üstünde duran ince bir çizgi, siz aşağı indikçe soldan sağa dolar.
#progress { transform-origin: left; animation: progressBar linear; animation-timeline: scroll(); } @keyframes progressBar { from { transform: scaleX(0); } to { transform: scaleX(1); } } Süre yazmadığımıza dikkat edin. Süreyi kaydırma belirliyor: çizelgenin başı sayfanın tepesi, sonu en altı. scroll() parametresiz bırakıldığında en yakın kaydırılabilir atayı arar. Sayfanın kendisini kastediyorsanız scroll(root block) yazmak niyeti daha açık bırakır ve araya sonradan bir kaydırma kutusu girdiğinde animasyonun sessizce başka bir yere bağlanmasını engeller.
view(): ögenin kendi görünürlüğü
İkinci kaynak, ögenin görüş alanına girip çıkma süreci. JavaScript tarafındaki Intersection Observer ile aynı soruyu cevaplar, ama gözlemci kurmanız, callback yazmanız ve temizlemeniz gerekmez.
.kart { animation: fadeIn linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } } animation-range burada işin yarısını yapıyor. Varsayılan aralık, ögenin alttan girmeye başladığı andan üstten tamamen çıktığı ana kadardır; bu da kartın ekranın ortasında tam görünürken çoktan solmaya başlaması demektir. entry 0% entry 100% dediğinizde animasyon yalnızca giriş boyunca çalışır, öge tamamen göründüğünde biter ve orada kalır.
both anahtar kelimesini atlamayın. Fill mode olmadan aralığın dışında kalan öge keyframe'lerin uygulanmadığı hâline döner, yani belirmesi gereken kart bir anda görünüp kaybolur.
Sessizce çalışmayan iki durum
Birincisi kısayol sırası. animation kısayolu, yazmadığınız alt özellikleri varsayılana çeker ve animation-timeline da bunlara dahildir. Yani şu sıralama animasyonu saate geri bağlar:
.kart { animation-timeline: view(); animation: fadeIn linear both; /* timeline burada auto'ya döndü */ } Bir okuma çubuğunu bu yüzden yarım gün kurcaladım, timeline satırı doğruydu ama iki satır aşağıdaki kısayol onu siliyordu. Kural basit: animation-timeline her zaman kısayoldan sonra gelsin.
İkincisi kaydırma kutusunun var olup olmadığı. scroll() ata zincirinde kaydırılabilir bir kutu bulamazsa animasyon hiç başlamaz, konsola da bir şey düşmez. Bunun ters yönü de var: overflow: hidden tanımlı bir kutu görsel olarak kaydırma çubuğu göstermese bile teknik olarak kaydırılabilirdir, dolayısıyla scroll() sayfa yerine ona bağlanabilir. Sadece taşanı kesmek istiyorsanız overflow: clip kullanın; o bir kaydırma kutusu üretmez.
Destek ve hareket hassasiyeti
Özellik Chromium'da 115 ile geldi, sonrasında diğer motorlara da yayıldı, ama eski sürümler hâlâ dolaşımda. Neyse ki bozulma biçimi nazik: animation-timeline tanınmazsa animasyon normal süreli animasyon gibi bir kez çalışır. Bunu bile istemiyorsanız blok hâlinde koşullayın:
@supports (animation-timeline: scroll()) { .kart { animation: fadeIn linear both; animation-timeline: view(); } } @media (prefers-reduced-motion: reduce) { .kart { animation: none; } } İkinci blok tercih meselesi değil. Kaydırmaya bağlı hareket, vestibüler duyarlılığı olan kullanıcılarda en çok şikâyet edilen efekt türü; kullanıcı sistem ayarında azaltılmış hareket seçtiyse animasyonu tamamen kapatmak doğru cevaptır.
Performans tarafında ölçüt her zamanki gibi: transform ve opacity compositor'da işlenir, width, top ya da margin her karede yeniden yerleşim ister. Scroll-driven animasyonların kazancı, JavaScript'i ana iş parçacığından çıkarmasıdır; yanlış özelliği animasyonlarsanız o kazancı geri verirsiniz.
Kaynak