Teknik Animasi CSS Berbasis Waktu
(yuanchuan.dev)- Seiring meningkatnya dukungan fungsi matematika CSS, pendekatan menghitung status animasi dengan variabel tick waktu
--talih-alih keyframes kembali menjadi praktis - Dengan menggabungkan
@property --tdan animasi root berdurasi86400000ms, waktu dalam satuan milidetik akan bertambah dan dapat dihubungkan ke perhitungan properti sepertirotatedantranslate - Dengan
step(), frame rate dapat dibatasi seperti 8fps, 24fps, atau 60fps, dan berkat optimasi browser, frekuensi pembaruan di atas 60fps pun biasanya tidak menjadi masalah - Dengan
min(),mod(),sin(),pow(), danround(), nilai waktu dapat dibatasi, diulang, dibuat berosilasi, dan diberi easing untuk mengekspresikan custom easing serta perpindahan posisi tanpa keyframes css-doodlemenyediakan notasi singkat seperti@t,@T, dan@TS, sehingga demo yang banyak memakai rumus matematika dapat ditulis lebih pendek dan dieksperimenkan lebih cepat
Membuat tick waktu sebagai variabel CSS
- Pendekatan lama memiliki cakupan penerapan yang terbatas karena sulit melakukan perhitungan matematika kompleks di CSS
- Saat ini CSS mendukung fungsi matematika yang dibutuhkan seperti
mod(),round(), dan fungsi trigonometri, sehingga animasi berbasis waktu dapat dicoba kembali - Untuk melihat demo, mungkin perlu mengaktifkan Experimental feature flags
Cara kerja dasar
- Seperti JavaScript, CSS tidak dapat memulai timer secara langsung, tetapi dengan CSS Houdini API kita dapat mendefinisikan variabel kustom
--tuntuk melacak waktu dalam satuan milidetik - Contoh dasar mendeklarasikan
@property --tsebagai<integer>, mengubahnya dari0hingga86400000di@keyframes tick, lalu menerapkan animasi86400000ms linear infinitepada:root --tbertambah1setiap 1 milidetik dan menjadi1000dalam 1 detik- Dengan
counter(), nilai--tsaat ini dapat ditampilkan di layar - Jika perhitungan berbasis
--tdihubungkan ke properti, sepertirotate: calc(var(--t) * .001turn), nilainya berubah seiring waktu dan menjadi animasi
Mengontrol frame rate
- Untuk animasi yang mulus, frekuensi pembaruan 60fps sudah cukup
- Karena ada optimasi rendering browser, frekuensi pembaruan yang lebih tinggi dari 60fps pun biasanya tidak menjadi masalah
- Jika perlu, frame rate dapat dibatasi langsung dengan menggunakan step() pada
animation-timing-function- 8fps:
step(calc(86400000/(1000/8))) - 24fps:
step(calc(86400000/(1000/24))) - 60fps:
step(calc(86400000/(1000/60)))
- 8fps:
Mengubah nilai waktu yang terus bertambah menjadi nilai animasi
- Nilai
--tterus bertambah ke satu arah - Nilai
angletidak masalah meski melebihi360deg, tetapi tidak semua properti CSS memperlakukan nilai secara siklik translate: calc(var(--t) * .001px)akan terus memindahkan kotak ke kanan-
Berhenti dengan min()
- Untuk menghentikannya segera setelah mencapai offset tertentu, min() dapat digunakan
translate: min(270px, calc(var(--t) * .5px))membatasi nilai perpindahan ke 270px- Untuk mengontrol durasi secara tepat,
--titu sendiri dapat dibatasi translate: calc(min(3000, var(--t)) * (270px / 3000))- Perhitungan ini membuatnya bergerak 270px selama 3 detik
-
Mengulang dengan mod()
- Untuk membuat kotak kembali mulai dari awal setelah bergerak ke kanan, gunakan mod()
- Offset dapat dibuat berulang dengan
translate: calc(mod(var(--t)/4, 270) * 1px)
-
Membuat gerakan bolak-balik dengan sin()
- Gerakan bolak-balik dapat diekspresikan dengan sin()
- Nilai waktu dihubungkan ke fungsi trigonometri seperti
translate: calc(sin(mod(var(--t)/135, 270)) * 135px)
Fungsi custom easing
- Dengan fungsi matematika CSS dan variabel
--t, kita dapat membuat custom easing yang mungkin sulit dicapai dengancubic-bezier() - Pertama, batasi
--tke nilai antara0dan1--t01: calc(min(1000, var(--t)) / 1000)berubah dari 0 ke 1 selama 1 detik
-
ease-out-cubic
ease-out-cubicterdiri dari rumus1 - pow(1 - t, 3)- Setelah membuat nilai
--ease-out-cubic, hubungkan ketranslate: calc(var(--ease-out-cubic) * 270px)
-
ease-out-elastic
ease-out-elasticterdiri dari rumuspow(2, -10t) * sin((10t - .75) * 2/3 * PI) + 1- Dengan cara yang sama, buat nilai
--ease-out-elasticlalu kalikan dengantranslateuntuk menerapkannya pada gerakan 270px
Memperpendek rumus dengan css-doodle
- Semakin kompleks rumus,
var()dancalc()membuat kode semakin sulit dibaca - Versi terbaru css-doodle menambahkan fungsi @t untuk mengekspresikan
--t, dan dapat menerima ekspresi matematika sederhana langsung di dalam argumennya - Ekspresi
rotatemenjadi lebih pendek seperti berikut- Sebelumnya:
rotate: calc(mod(var(--t) / 1000, 10) * 5deg) css-doodle:rotate: @t(/1000, %10, *5deg)
- Sebelumnya:
- Animasi berbasis matematika dapat dibuat dengan kode pendek tanpa menulis keyframes
- Dengan mengganti parameter, hasil baru dapat dieksperimenkan dengan cepat
-
@T dan @TS
- Selain
@t, huruf besar @T menunjukkan time ticks sejak awal hari - @TS adalah shorthand untuk
@t(/1000)dan melacak waktu dalam satuan detik - Contoh jam dapat dilihat di CodePen
- Jarum detik:
rotate: @TS(*6, %360deg) - Jarum menit:
rotate: @TS(/60, *6, %360deg) - Jarum jam:
rotate: @TS(/60, /12, *6, %360deg)
- Selain
-
Membuat jarum detik meloncat dengan round()
- Untuk membuat jarum detik bergerak seperti melompat, round() dapat digunakan
- Parameter ketiga
round()menentukan interval pembulatan - Pada jam, satu langkah adalah
360 / 60 = 6deg, jadi gunakanrotate: round(down, @TS(*6, %360deg), 6deg)
Demo dan poin penerapan
- Contoh yang menganimasikan warna dan posisi bersama-sama dapat dilihat di CodePen
- Contoh animasi warna teks ada di CodePen
- Keyframes bisa terlihat lebih intuitif, tetapi dalam adegan demo yang memiliki banyak perhitungan matematika dan variabel input, cara menggunakan waktu sebagai variabel membuat berbagai hasil lebih mudah dibuat
- Pada pembaruan 17 Mei 2024, demo animasi warna teks ditambahkan
1 komentar
Komentar di Hacker News
Jika ingin mengontrol progres dengan JS, memakai nilai animation-delay negatif juga direkomendasikan
Misalnya,
animation-delay: -1500mslangsung memulai animasi, tetapi melompat ke titik 1,5 detikJika nilai ini dikontrol lewat JS, animasi CSS pada dasarnya bisa di-scrub dari JS, sehingga semua animasi dapat diselaraskan dengan loop tick compute-update-render ala game engine
https://developer.mozilla.org/en-US/docs/Web/CSS/animation-d...
Begitu sedikit saja lebih kompleks daripada fungsi easing sederhana atau keyframe dasar dengan satu-dua channel, pendekatan ini cepat menemui batasnya
Beberapa tahun terakhir saya memakai Theatre.js dan cukup puas
Ini adalah library yang terbagi menjadi UI studio untuk mengedit keyframe dan kurva Bezier di timeline, serta runtime yang menginterpolasi keyframe tersebut berdasarkan timeline
Layak dicoba jika perlu menyelaraskan beberapa animasi agar bergerak bersama
https://www.theatrejs.com/
Sangat mengesankan, tetapi entah kenapa juga terasa seperti baru sekarang mendekati hal yang puluhan tahun lalu sudah bisa dilakukan dengan Flash
Saya tidak berharap Flash kembali, tetapi ingin ada tool yang lebih ramah pengguna untuk membuat animasi CSS
CSS kini sudah punya dukungan yang cukup untuk fungsi matematika seperti
mod(),round(), dan fungsi trigonometriCSS memang tidak bisa memulai timer seperti JavaScript, tetapi sekarang dengan CSS Houdini API kita bisa mendefinisikan variabel kustom yang melacak waktu dalam satuan milidetik
Namun, kalau sudah ada JavaScript, mengapa semua ini diperlukan?
Bukankah lapisan rendering seharusnya fokus pada primitive untuk menggambar? Mengapa memasukkan lebih banyak fungsi tingkat atas ke sana?
Jika menjalankan fungsi trigonometri di JS untuk animasi, kemungkinan Anda juga memanipulasi DOM untuk memperbarui UI setiap milidetik, dan biayanya sangat besar
Rendering digerakkan oleh DOM yang disusun dengan HTML atau diperbarui dengan JS
CSS hanya berada di atasnya dengan meneruskan parameter ke painting engine tentang apa yang harus dilakukan pada DOM, sambil menimpa nilai default
CSS bisa menambahkan blok DOM, mengubah perilaku penentuan posisi dengan algoritme kompleks, dan bahkan margin sebenarnya tidak sesederhana itu
Saya tidak menganggapnya solusi yang hebat, tetapi tampaknya ini bermula dari upaya agar tidak perlu memperbarui kode HTML hanya untuk mengubah warna saat DOM dirender
Mungkin karena memperbarui kode HTML sama sekali tidak menyenangkan, tetapi menurut saya sejak awal mereka menyelesaikan masalah yang keliru
Memang, saat itu juga era “webmaster”
Lebih mudah dibaca jika di dalam logika fetch tidak tercampur logika progres geometri elemen DOM loader, misalnya perhitungan sudut rotasi dan penerapan inline style
Saya tahu sekarang cara memisahkan cokelat dan selai kacang tidak populer, tetapi konvensi seperti ini memberi batasan yang memudahkan menebak kode berada di mana dan harus diletakkan di mana
Selain bercanda, CSS bersifat deklaratif, dan menurut saya wajar jika masalah yang bisa diselesaikan dengan JS dan CSS saling tumpang tindih
Fitur-fitur baru yang belakangan ditambahkan ke CSS benar-benar menarik, dan berkurangnya kode yang harus diinterpretasikan adalah hal baik
CSS kustom
@propertyyang digunakan dalam artikel ini bagus, dan dukungan browser juga 88% [1]Namun, perlu berhati-hati terhadap perbedaan perilaku antar-browser saat menetapkan
initial-valuefallbackChrome memakai
initial-valuejika variabel CSS tidak didefinisikan atau disetel ke nilai yang salahFirefox memakai
initial-valuehanya ketika variabel tidak didefinisikanDi sebagian besar proyek ini tidak akan jadi masalah, tetapi dalam proyek terbaru kami harus menetapkan nilai default lewat JavaScript di Firefox untuk menyamakan perbedaan implementasi browser
[1] https://caniuse.com/?search=%40property
about:configlalu aktifkanlayout.css.properties-and-values.enabledMengambil nilai properti yang didefinisikan di
:root{}:getComputedStyle(document.documentElement).getPropertyValue("--some-custom-css-var");Menetapkan nilai properti:
document.documentElement.style.setProperty("--some-custom-css-var", "some value");Pada browser yang belum mengaktifkan dukungan CSS
@property, ini bisa dipakai seperti polyfillMenariknya, di Android Chrome terbaru, demo sebelum
mod()berjalan tanpa Experimental feature flags, tetapimod()dansin()tidak melakukan apa punAlasan saya menginginkan ini selama beberapa waktu adalah karena ingin membuat sesuatu seperti box-breathing
Saya ingin bisa menyesuaikan semua tahap tarik napas–tahan–embuskan–tahan sesuai tubuh dan efek yang diinginkan
Tanpa pendekatan seperti di halaman ini, saya tidak menemukan cara menerapkannya tanpa JS atau tanpa kompleksitas yang tidak masuk akal
Wah, stylesheet! Demo-demo di halaman ini benar-benar kreatif
Artikelnya benar-benar ditulis dengan baik
Chrome belum merilis dukungan CSS
mod()secara resmi, jadi jika tidak memakai rilis pratinjau Chrome, sebagian besar contoh di halaman itu tidak beranimasiJika tidak membutuhkan kontrol tick dan hanya ingin animasi CSS yang mulus di semua browser, teknik FLIP berguna
https://medium.com/outsystems-experts/flip-your-60-fps-anima...
Animasi di bagian bawah halaman sangat mengesankan
Terlihat seperti satu video, bukan elemen-elemen terpisah
https://RTCode.io adalah playground web real-time yang berjalan tanpa refresh dan tanpa reset status, sehingga bisa sangat membantu bagi orang yang menangani animasi atau transisi CSS
Demonya ada di https://RTCode.io
Untuk mengambil Pen, ubah hostname di URL menjadi
xcodepen.io