7 poin oleh GN⁺ 2024-05-06 | 1 komentar | Bagikan ke WhatsApp
  • Seiring meningkatnya dukungan fungsi matematika CSS, pendekatan menghitung status animasi dengan variabel tick waktu --t alih-alih keyframes kembali menjadi praktis
  • Dengan menggabungkan @property --t dan animasi root berdurasi 86400000ms, waktu dalam satuan milidetik akan bertambah dan dapat dihubungkan ke perhitungan properti seperti rotate dan translate
  • 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(), dan round(), nilai waktu dapat dibatasi, diulang, dibuat berosilasi, dan diberi easing untuk mengekspresikan custom easing serta perpindahan posisi tanpa keyframes
  • css-doodle menyediakan 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 --t untuk melacak waktu dalam satuan milidetik
  • Contoh dasar mendeklarasikan @property --t sebagai <integer>, mengubahnya dari 0 hingga 86400000 di @keyframes tick, lalu menerapkan animasi 86400000ms linear infinite pada :root
  • --t bertambah 1 setiap 1 milidetik dan menjadi 1000 dalam 1 detik
  • Dengan counter(), nilai --t saat ini dapat ditampilkan di layar
  • Jika perhitungan berbasis --t dihubungkan ke properti, seperti rotate: 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)))

Mengubah nilai waktu yang terus bertambah menjadi nilai animasi

  • Nilai --t terus bertambah ke satu arah
  • Nilai angle tidak masalah meski melebihi 360deg, 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, --t itu 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 dengan cubic-bezier()
  • Pertama, batasi --t ke nilai antara 0 dan 1
    • --t01: calc(min(1000, var(--t)) / 1000) berubah dari 0 ke 1 selama 1 detik
  • ease-out-cubic

    • ease-out-cubic terdiri dari rumus 1 - pow(1 - t, 3)
    • Setelah membuat nilai --ease-out-cubic, hubungkan ke translate: calc(var(--ease-out-cubic) * 270px)
  • ease-out-elastic

    • ease-out-elastic terdiri dari rumus pow(2, -10t) * sin((10t - .75) * 2/3 * PI) + 1
    • Dengan cara yang sama, buat nilai --ease-out-elastic lalu kalikan dengan translate untuk menerapkannya pada gerakan 270px

Memperpendek rumus dengan css-doodle

  • Semakin kompleks rumus, var() dan calc() 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 rotate menjadi lebih pendek seperti berikut
    • Sebelumnya: rotate: calc(mod(var(--t) / 1000, 10) * 5deg)
    • css-doodle: rotate: @t(/1000, %10, *5deg)
  • 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)
  • 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 gunakan rotate: 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

 
GN⁺ 2024-05-06
Komentar di Hacker News
  • Jika ingin mengontrol progres dengan JS, memakai nilai animation-delay negatif juga direkomendasikan
    Misalnya, animation-delay: -1500ms langsung memulai animasi, tetapi melompat ke titik 1,5 detik
    Jika 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...

    • Kalau begitu, bukankah animasi berbasis offset scroll gaya iOS juga jadi memungkinkan?
  • 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 trigonometri
    CSS 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?

    • Jangan lupa bahwa animasi CSS diakselerasi hardware
      Jika menjalankan fungsi trigonometri di JS untuk animasi, kemungkinan Anda juga memanipulasi DOM untuk memperbarui UI setiap milidetik, dan biayanya sangat besar
    • CSS bukan lapisan rendering
      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”
    • Salah satu kelebihan yang terpikir adalah pemisahan antara logika aplikasi dan presentasi
      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
    • JS pada dasarnya single-threaded; tentu ada worker, tetapi apa pun yang bisa dialihkan ke tempat lain bagus untuk menjaga UI tetap pada frame rate yang stabil
    • Mari tunggu sampai WebSocket masuk ke CSS!
      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 @property yang digunakan dalam artikel ini bagus, dan dukungan browser juga 88% [1]
    Namun, perlu berhati-hati terhadap perbedaan perilaku antar-browser saat menetapkan initial-value fallback
    Chrome memakai initial-value jika variabel CSS tidak didefinisikan atau disetel ke nilai yang salah
    Firefox memakai initial-value hanya ketika variabel tidak didefinisikan
    Di 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

    • Jika ingin mencoba demo di Firefox, buka about:config lalu aktifkan layout.css.properties-and-values.enabled
    • Cara menetapkan nilai properti dari JavaScript saat diperlukan adalah seperti ini
      Mengambil 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 polyfill
  • Menariknya, di Android Chrome terbaru, demo sebelum mod() berjalan tanpa Experimental feature flags, tetapi mod() dan sin() tidak melakukan apa pun

  • Alasan 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

    • Bukankah itu hanya kurva animasi CSS?
  • 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 beranimasi
    Jika 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

    • Ada yang pernah memakai RTCode? Terlihat menarik, tetapi melihat homepage-nya agak membingungkan apakah ini pengganti CodePen dengan dukungan real-time, atau juga bisa dipakai di produksi