Zaman Tabanlı CSS Animasyon Teknikleri
(yuanchuan.dev)- CSS matematik fonksiyonlarına verilen desteğin artmasıyla,
keyframesyerine zaman tick değişkeni--tile animasyon durumunu hesaplama yaklaşımı yeniden pratik hale geldi @property --tile86400000msuzunluğunda bir root animasyonu birleştirildiğinde, milisaniye düzeyinde artan bir zaman elde edilebilir ve bu zamanrotate,translategibi özellik hesaplamalarına bağlanabilirstep()kullanılırsa 8fps, 24fps, 60fps gibi frame rate sınırlandırılabilir; tarayıcı optimizasyonları sayesinde 60fps'in üzerindeki güncelleme sıklığı da genelde sorun yaratmazmin(),mod(),sin(),pow(),round()ile zaman değeri sınırlandırılıp tekrarlanabilir, salınım ve easing uygulanabilir; böylece özel easing ve konum hareketlerikeyframesolmadan ifade edilebilircss-doodle,@t,@T,@TSgibi kısaltmalar sunarak matematiksel ifadelerin yoğun olduğu demoların daha kısa yazılmasını ve daha hızlı denenmesini sağlar
Zaman tick'ini CSS değişkenine dönüştürmek
- Geçmişteki yaklaşım, CSS içinde karmaşık matematik hesaplamaları yapmak zor olduğundan sınırlı bir kullanım alanına sahipti
- Günümüz CSS'i,
mod(),round(), trigonometrik fonksiyonlar gibi gerekli matematik fonksiyonlarını desteklediği için zaman tabanlı animasyonlar yeniden denenebilir hale geldi - Demoyu görmek için Experimental feature flags etkinleştirilmesi gerekebilir
Temel çalışma şekli
- CSS, JavaScript gibi doğrudan zamanlayıcı başlatamaz; ancak CSS Houdini API ile özel değişken
--ttanımlanarak milisaniye düzeyinde zaman takip edilebilir - Temel örnekte
@property --t,<integer>olarak bildirilir;@keyframes tickiçinde0ile86400000arasında değiştirilir ve:rootüzerine86400000ms linear infiniteanimasyonu uygulanır --t, her 1 milisaniyede1artar ve 1 saniyede1000olurcounter()kullanılarak mevcut--tdeğeri ekranda gösterilebilirrotate: calc(var(--t) * .001turn)gibi--ttabanlı hesaplamalar özelliklere bağlandığında, zaman aktıkça değer değişir ve animasyona dönüşür
Frame rate kontrolü
- Akıcı animasyonlar için 60fps güncelleme sıklığı yeterlidir
- Tarayıcıların render optimizasyonları sayesinde güncelleme sıklığı 60fps'in üzerine çıksa da genelde sorun olmaz
- Gerekirse
animation-timing-functioniçinde step() kullanılarak frame rate doğrudan sınırlandırılabilir- 8fps:
step(calc(86400000/(1000/8))) - 24fps:
step(calc(86400000/(1000/24))) - 60fps:
step(calc(86400000/(1000/60)))
- 8fps:
Sürekli artan zaman değerini animasyon değerine dönüştürmek
--tdeğeri tek yönde sürekli artarangledeğeri360degdeğerini aşsa da sorun olmaz; ancak tüm CSS özellikleri değeri döngüsel olarak işlemeztranslate: calc(var(--t) * .001px)kutuyu sürekli sağa taşır-
min() ile durdurmak
- Belirli bir ofsete ulaşır ulaşmaz durdurmak için min() kullanılabilir
translate: min(270px, calc(var(--t) * .5px))hareket değerini 270px ile sınırlar- Süreyi tam kontrol etmek için
--tdeğerinin kendisi sınırlandırılabilir translate: calc(min(3000, var(--t)) * (270px / 3000))- Bu hesaplama, 3 saniyede 270px hareket sağlar
-
mod() ile tekrarlamak
- Kutu sağa gittikten sonra başa dönsün isteniyorsa mod() kullanılır
translate: calc(mod(var(--t)/4, 270) * 1px)ile ofset tekrarlanabilir
-
sin() ile ileri-geri hareket oluşturmak
- İleri-geri hareket sin() ile ifade edilebilir
translate: calc(sin(mod(var(--t)/135, 270)) * 135px)gibi, zaman değeri trigonometrik fonksiyona bağlanır
Özel easing fonksiyonları
- CSS matematik fonksiyonları ve
--tdeğişkeniyle,cubic-bezier()ile elde edilmesi zor olabilecek özel easing fonksiyonları oluşturulabilir - Önce
--t,0ile1arasındaki bir değere sınırlandırılır--t01: calc(min(1000, var(--t)) / 1000)1 saniye boyunca 0'dan 1'e değişir
-
ease-out-cubic
ease-out-cubic,1 - pow(1 - t, 3)hesabından oluşur--ease-out-cubicdeğeri oluşturuluptranslate: calc(var(--ease-out-cubic) * 270px)içine bağlanır
-
ease-out-elastic
ease-out-elastic,pow(2, -10t) * sin((10t - .75) * 2/3 * PI) + 1hesabından oluşur- Aynı şekilde
--ease-out-elasticdeğeri oluşturuluptranslateile çarpılarak 270px harekete uygulanır
css-doodle ile formülleri kısaltmak
- Formüller karmaşıklaştıkça
var()vecalc(), kodun okunmasını zorlaştırır - css-doodle son sürümü,
--tifadesini temsil eden @t fonksiyonu ekledi; bu sayede parametrelerin içinde basit matematik ifadeleri doğrudan yazılabilir rotateifadesi şu şekilde kısalır- Önceki:
rotate: calc(mod(var(--t) / 1000, 10) * 5deg) css-doodle:rotate: @t(/1000, %10, *5deg)
- Önceki:
keyframesyazmadan da kısa kodla matematik tabanlı animasyonlar oluşturulabilir- Parametreler değiştirilerek yeni sonuçlar hızlıca denenebilir
-
@T ve @TS
@tdışında büyük harfli @T, günün başlangıcından itibaren geçen time tick'leri ifade eder- @TS,
@t(/1000)için shorthand'tir ve zamanı saniye cinsinden takip eder - Saat örneği CodePen üzerinde görülebilir
- Saniye kolu:
rotate: @TS(*6, %360deg) - Dakika kolu:
rotate: @TS(/60, *6, %360deg) - Saat kolu:
rotate: @TS(/60, /12, *6, %360deg)
-
round() ile saniye kolunda sıçramalı hareket
- Saniye kolunun sıçrayarak hareket etmesi için round() kullanılabilir
round()fonksiyonunun üçüncü parametresi, yuvarlama aralığını belirler- Saatte bir adım
360 / 60 = 6degolduğundanrotate: round(down, @TS(*6, %360deg), 6deg)kullanılır
Demolar ve uygulama noktaları
- Renk ve konumu birlikte animasyonlayan örnek CodePen üzerinde görülebilir
- Metin rengi animasyonu örneği CodePen bağlantısında yer alır
keyframesdaha sezgisel görünebilir; ancak matematik hesaplarının ve giriş değişkenlerinin fazla olduğu demo sahnelerinde zamanı değişken olarak kullanma yaklaşımı, daha çeşitli sonuçlar üretmeyi kolaylaştırır- 17 Mayıs 2024 güncellemesiyle metin rengi animasyonu demosu eklendi
1 yorum
Hacker News yorumları
İlerlemeyi JS ile kontrol etmek istiyorsanız negatif animation-delay değerleri kullanmayı da öneririm.
Örneğin
animation-delay: -1500ms, animasyonu hemen başlatır ama 1,5 saniye noktasına atlar.Bu değeri JS ile kontrol ederseniz CSS animasyonlarını JS tarafında fiilen scrub edebilirsiniz; böylece tüm animasyonları oyun motoru tarzı compute-update-render tick döngüsüyle hizalayabilirsiniz.
https://developer.mozilla.org/en-US/docs/Web/CSS/animation-d...
Basit bir easing fonksiyonunun ya da bir iki kanallı temel keyframe'in biraz ötesine geçince bu yaklaşımın sınırlarına hızla çarpıyorsunuz.
Son birkaç yıldır Theatre.js kullanıyorum ve oldukça memnunum.
Keyframe'leri ve Bézier eğrilerini bir zaman çizelgesinde düzenleyen bir stüdyo arayüzü ile bu keyframe'leri zaman çizelgesine göre enterpole eden bir runtime'dan oluşan bir kütüphane.
Birden fazla animasyonu uyumlu hareket ettirmeniz gerekiyorsa denemeye değer.
https://www.theatrejs.com/
Çok etkileyici; ama bir yandan da sanki onlarca yıl önce Flash ile yapılabilen şeye ancak şimdi yaklaşıyormuşuz gibi hissettiriyor.
Flash'ın geri dönmesini istemiyorum ama CSS animasyonları oluşturmak için daha kullanıcı dostu araçlar olsa iyi olurdu.
CSS artık
mod(),round(), trigonometrik fonksiyonlar gibi matematik fonksiyonları için yeterli desteğe sahip.CSS, JavaScript gibi zamanlayıcı başlatamaz; ancak bugünlerde CSS Houdini API ile milisaniye düzeyinde zamanı izleyen özel değişkenler tanımlanabiliyor.
Peki JavaScript varken tüm bunlara neden ihtiyaç var?
Çizim katmanı çizim temel öğelerine odaklanmamalı mı? Neden oraya daha fazla üst katman işlevi ekleniyor?
Animasyon için JS'te trigonometrik fonksiyonlar çalıştırıyorsanız, muhtemelen her milisaniyede UI'ı güncellemek için DOM'u da manipüle ediyorsunuzdur; bunun maliyeti çok yüksek.
Çizimi, HTML ile oluşturulan veya JS ile güncellenen DOM yönlendirir.
CSS ise DOM üzerinde ne yapılacağına dair parametreleri painting engine'e iletip varsayılanları ezerek bunun üstüne eklenir.
DOM blokları ekleyebilir, karmaşık algoritmalarla konumlandırma davranışını değiştirebilir; margin bile aslında o kadar basit değildir.
Harika bir çözüm olduğunu düşünmüyorum; ama DOM render edilirken renkleri değiştirmek için HTML kodunu güncellemek zorunda kalınmasın diye başlamış gibi görünüyor.
Muhtemelen HTML kodunu güncellemek hiç keyifli olmadığı içindi; ama bence baştan yanlış problemi çözmüşler.
O dönemin “webmaster” dönemi olması da var tabii.
Fetch mantığının içinde loader DOM öğesinin geometrik ilerleme mantığı, örneğin dönüş açısını hesaplama ve inline style uygulama gibi şeyler karışmadığında okumak daha kolay oluyor.
Günümüzde çikolata ile fıstık ezmesini ayrı tutmanın pek popüler olmadığını biliyorum; ama bu tür teamüller, kodun nerede olacağını ve nereye konması gerektiğini kestirmeyi kolaylaştıran sınırlar çizer.
Şaka bir yana, CSS deklaratiftir ve JS ile CSS'in çözebildiği problemlerin çakışması doğal bence.
CSS'e son dönemde eklenen yeni özellikler gerçekten heyecan verici ve yorumlanan kodun azalması iyi bir şey.
Yazıda kullanılan özel CSS
@propertyharika ve tarayıcı desteği de %88 [1].Ancak yedek
initial-valueayarlanırken tarayıcılar arasındaki davranış farklarına dikkat etmek gerekiyor.Chrome, CSS değişkeni tanımlı değilse veya geçersiz bir değere ayarlanmışsa
initial-valuekullanıyor.Firefox ise
initial-valuedeğerini yalnızca değişken tanımlı olmadığında kullanıyor.Çoğu projede sorun olmaz; ama yakın tarihli bir projede tarayıcı implementasyon farklarını eşitlemek için Firefox'ta varsayılan değeri JavaScript ile ayarlamak zorunda kaldık.
[1] https://caniuse.com/?search=%40property
about:configsayfasına gidiplayout.css.properties-and-values.enabledseçeneğini açabilirsiniz.:root{}içinde tanımlı özellik değerini almak:getComputedStyle(document.documentElement).getPropertyValue("--some-custom-css-var");Özellik değerini ayarlamak:
document.documentElement.style.setProperty("--some-custom-css-var", "some value");CSS
@propertydesteği henüz açık olmayan tarayıcılarda polyfill gibi kullanılabilir.Güncel Android Chrome'da ilginç biçimde Experimental feature flags olmadan da
mod()öncesi demolar çalışıyor; amamod()vesin()hiçbir şey yapmıyor.Bir süredir bunu istememin nedeni box-breathing gibi bir şey yapmak istememdi.
Nefes alma-durma-verme-durma aşamalarını bedene ve istenen etkiye göre tamamen ayarlayabilmek istiyordum.
Bu sayfadaki gibi bir yöntem olmadan bunu JS'siz ya da saçma derecede karmaşık hale getirmeden uygulamanın bir yolunu bulamamıştım.
Vay canına, stil sayfası! Bu sayfadaki demolar gerçekten yaratıcı.
Yazı gerçekten çok iyi yazılmış.
Chrome, CSS
mod()desteğini henüz kararlı sürümde yayınlamadığı için Chrome önizleme sürümü kullanmıyorsanız sayfadaki örneklerin çoğu animasyonlu çalışmıyor.Tick kontrolüne ihtiyacınız yoksa ve tüm tarayıcılarda yalnızca akıcı CSS animasyonları istiyorsanız FLIP tekniği kullanışlıdır.
https://medium.com/outsystems-experts/flip-your-60-fps-anima...
Sayfanın altındaki animasyon çok etkileyici.
Tek tek öğelerden ziyade bir video gibi görünüyor.
https://RTCode.io yenileme olmadan, durum sıfırlanmadan çalışan gerçek zamanlı bir web playground olduğu için CSS animasyonları veya transition'larla uğraşanlara çok yardımcı olabilir.
Demo https://RTCode.io üzerinde.
Bir Pen'i içe aktarmak için URL'deki host adını
xcodepen.ioolarak değiştirmeniz yeterli.