Mengorkestrasi Kompleksitas Dengan Web Animations API
Diterbitkan: 2022-03-10Tidak ada jalan tengah antara transisi sederhana dan animasi kompleks. Anda baik-baik saja dengan apa yang disediakan Transisi dan Animasi CSS atau Anda tiba-tiba membutuhkan semua kekuatan yang bisa Anda dapatkan. Web Animations API memberi Anda banyak alat untuk bekerja dengan animasi. Tetapi Anda perlu tahu cara menanganinya. Artikel ini akan memandu Anda melalui poin dan teknik utama yang mungkin membantu Anda menangani animasi yang rumit sambil tetap fleksibel.
Sebelum kita masuk ke artikel, penting bagi Anda untuk terbiasa dengan dasar-dasar Web Animations API dan JavaScript. Untuk memperjelas dan menghindari gangguan dari masalah yang dihadapi, contoh kode yang diberikan adalah sederhana. Tidak akan ada yang lebih kompleks dari fungsi dan objek. Sebagai titik masuk yang bagus ke dalam animasi itu sendiri, saya akan menyarankan MDN sebagai referensi umum, seri Daniel C. Wilson yang luar biasa, dan CSS Animations vs Web Animations API oleh Ollie Williams. Kami tidak akan membahas cara untuk menentukan efek dan menyetelnya untuk mencapai hasil yang Anda inginkan. Artikel ini mengasumsikan bahwa Anda telah mendefinisikan animasi dan membutuhkan ide dan teknik untuk menanganinya.
Kami mulai dengan ikhtisar antarmuka dan untuk apa mereka. Kemudian kita akan melihat waktu dan tingkat kontrol untuk menentukan apa, kapan, dan untuk berapa lama. Setelah itu, kita akan belajar bagaimana memperlakukan beberapa animasi sebagai satu dengan membungkusnya dalam objek. Itu akan menjadi awal yang baik dalam perjalanan Anda menggunakan Web Animations API.
Antarmuka
Web Animations API memberi kita dimensi kontrol baru. Sebelum itu, Transisi dan Animasi CSS sambil memberikan cara yang ampuh untuk mendefinisikan efek masih memiliki satu titik aktuasi . Seperti saklar lampu, itu hidup atau mati. Anda bisa bermain dengan penundaan dan fungsi easing untuk menciptakan efek yang cukup kompleks. Namun, pada titik tertentu, itu menjadi rumit dan sulit untuk dikerjakan.
Web Animations API mengubah satu titik aktuasi ini menjadi kontrol penuh atas pemutaran . Sakelar lampu berubah menjadi sakelar peredup dengan penggeser. Jika mau, Anda dapat mengubahnya menjadi rumah pintar secara keseluruhan, karena selain kontrol pemutaran, Anda sekarang dapat menentukan dan mengubah efek saat runtime. Anda sekarang dapat menyesuaikan efek dengan konteks atau Anda dapat menerapkan editor animasi dengan pratinjau waktu nyata.
Kita mulai dengan antarmuka Animasi. Untuk mendapatkan objek animasi, kita bisa menggunakan metode Element.animate
. Anda memberinya bingkai utama dan opsi dan segera memainkan animasi Anda. Apa yang juga dilakukannya adalah mengembalikan instance objek Animation
. Tujuannya adalah untuk mengontrol pemutaran.
Anggap saja sebagai pemutar kaset , jika Anda ingat ini. Saya sadar bahwa beberapa pembaca mungkin tidak akrab dengan apa itu. Tidak dapat dihindari bahwa setiap upaya untuk menerapkan konsep dunia nyata untuk menggambarkan hal-hal komputer yang abstrak akan berantakan dengan cepat. Tetapi biarkan ini meyakinkan Anda — seorang pembaca yang tidak tahu kegembiraan menggulung kaset dengan pensil — bahwa orang-orang yang tahu apa itu pemutar kaset akan semakin bingung di akhir artikel ini.
Bayangkan sebuah kotak. Ini memiliki slot di mana kaset pergi dan memiliki tombol untuk bermain, berhenti dan mundur. Itulah contoh antarmuka Animasi — kotak yang menyimpan animasi yang ditentukan dan menyediakan cara untuk berinteraksi dengan pemutarannya. Anda memberinya sesuatu untuk dimainkan dan itu memberi Anda kontrol kembali.
Kontrol yang Anda dapatkan sangat mirip dengan yang Anda dapatkan dari elemen audio dan video. Mereka adalah metode putar dan jeda , dan properti waktu saat ini. Dengan ketiga kontrol tersebut, Anda dapat membuat apa pun terkait pemutaran.
Kaset itu sendiri adalah paket yang berisi referensi ke elemen yang dianimasikan, definisi efek, dan opsi yang mencakup waktu antara lain. Dan itulah KeyframeEffect
. Kaset kami adalah sesuatu yang menyimpan semua rekaman dan info tentang panjang rekaman. Saya akan membiarkan imajinasi audiens yang lebih tua untuk mencocokkan semua properti itu dengan komponen kaset fisik. Apa yang akan saya tunjukkan adalah bagaimana tampilannya dalam kode.
Saat Anda membuat animasi melalui Element.animate
, Anda menggunakan pintasan yang melakukan tiga hal. Itu membuat instance KeyframeEffect
. Ini dimasukkan ke dalam contoh Animation
baru. Ini segera mulai memainkannya.
const animation = element.animate(keyframes, options);
Mari kita uraikan dan lihat kode setara yang melakukan hal yang sama.
const animation = new Animation( // (2) new KeyframeEffect(element, keyframes, options) // (1) ); animation.play(); (3)
Ambil kaset (1), masukkan ke pemutar (2), lalu tekan tombol Putar (3).
Inti dari mengetahui cara kerjanya di balik layar adalah untuk dapat memisahkan definisi bingkai utama dan memutuskan kapan akan memainkannya. Bila Anda memiliki banyak animasi untuk dikoordinasikan, mungkin akan membantu untuk mengumpulkan semuanya terlebih dahulu sehingga Anda tahu bahwa mereka siap untuk dimainkan. Menghasilkan mereka dengan cepat dan berharap mereka akan mulai bermain pada saat yang tepat bukanlah sesuatu yang ingin Anda harapkan. Terlalu mudah untuk mematahkan efek yang diinginkan dengan beberapa drag frame. Dalam hal urutan yang panjang, tarikan terakumulasi menghasilkan pengalaman yang sama sekali tidak meyakinkan.
Waktu
Seperti dalam komedi, waktu adalah segalanya dalam animasi. Untuk membuat efek bekerja, untuk mencapai perasaan tertentu, Anda harus mampu menyempurnakan cara properti berubah. Ada dua tingkat pengaturan waktu yang dapat Anda kendalikan di Web Animations API.
Pada tingkat properti individu, kami memiliki offset
. Offset memberi Anda kendali atas waktu properti tunggal . Dengan memberikan nilai dari nol hingga satu, Anda menentukan kapan setiap efek muncul. Ketika dihilangkan, itu sama dengan nol.
Anda mungkin ingat dari @keyframes
di CSS bagaimana Anda dapat menggunakan persentase alih-alih from
/ to
. Itulah yang dimaksud dengan offset
tetapi dibagi seratus. Nilai offset
adalah bagian dari durasi satu iterasi .
offset
memungkinkan Anda untuk mengatur bingkai utama dalam KeyframeEffect
. Menjadi offset angka relatif memastikan bahwa tidak peduli durasi atau kecepatan pemutaran, semua bingkai utama Anda dimulai pada saat yang sama relatif satu sama lain.
Seperti yang kami nyatakan sebelumnya, offset
adalah bagian dari durasi . Sekarang saya ingin Anda menghindari kesalahan dan kehilangan waktu saya dalam hal ini. Penting untuk dipahami bahwa durasi animasi tidak sama dengan durasi keseluruhan animasi. Biasanya, mereka sama dan itulah yang bisa membingungkan Anda, dan yang pasti membuat saya bingung.
Durasi adalah jumlah waktu dalam milidetik yang diperlukan untuk menyelesaikan satu iterasi. Ini akan sama dengan durasi keseluruhan secara default. Setelah Anda menambahkan penundaan atau menambah jumlah iterasi dalam durasi animasi berhenti memberi tahu Anda nomor yang ingin Anda ketahui. Itu penting untuk dipahami untuk menggunakannya untuk keuntungan Anda.
Saat Anda perlu mengoordinasikan pemutaran bingkai utama dalam konteks yang lebih besar, seperti pemutaran media, Anda perlu menggunakan opsi pengaturan waktu. Seluruh durasi animasi dari awal hingga acara “selesai” dalam persamaan berikut:
delay + (iterations × duration) + end delay
Anda dapat melihatnya beraksi di demo berikut:
Apa yang memungkinkan kita lakukan adalah menyelaraskan beberapa animasi dalam konteks media dengan panjang tetap. Menjaga durasi animasi yang diinginkan tetap utuh, Anda dapat "mengisinya" dengan delay
di awal dan delayEnd
di akhir untuk menyematkannya ke dalam konteks dengan durasi yang lebih lama. Jika Anda memikirkannya, delay
dalam pengertian ini akan bertindak seperti yang dilakukan offset dalam bingkai utama. Ingatlah bahwa penundaan diatur dalam milidetik sehingga Anda mungkin ingin mengubahnya menjadi nilai relatif.
Satu lagi opsi pengaturan waktu yang akan membantu menyelaraskan animasi adalah iterationStart
. Ini menetapkan posisi awal iterasi. Ikuti demo bola biliar. Dengan mengatur iterationStart
slider Anda dapat mengatur posisi awal bola dan rotasi, misalnya, Anda dapat mengaturnya untuk mulai melompat dari tengah layar dan membuat angka menjadi lurus di kamera di frame terakhir.
Kontrol Beberapa Sebagai Satu
Ketika saya bekerja di editor animasi untuk aplikasi presentasi, saya harus mengatur beberapa animasi untuk satu elemen pada garis waktu. Upaya pertama saya adalah menggunakan offset
untuk menempatkan animasi saya di titik awal yang tepat pada garis waktu.
Itu dengan cepat terbukti menjadi cara yang salah dalam menggunakan offset
. Dalam hal animasi bergerak UI khusus ini pada timeline dimaksudkan untuk menggeser posisi awalnya tanpa mengubah durasi animasi. Dengan offset
itu berarti saya perlu mengubah beberapa hal, offset
itu sendiri dan juga mengubah offset
penutupan untuk memastikan durasinya tidak berubah. Solusinya terbukti terlalu rumit untuk dipahami.
Masalah kedua datang dengan properti transform
. Karena fakta bahwa itu dapat mewakili beberapa perubahan karakteristik pada suatu elemen, itu bisa menjadi rumit untuk membuatnya melakukan apa yang Anda inginkan. Jika ada keinginan untuk mengubah properti tersebut secara independen satu sama lain, itu bisa menjadi lebih sulit. Perubahan fungsi skala mempengaruhi semua fungsi yang mengikutinya. Inilah mengapa itu terjadi.
Transform properti dapat mengambil beberapa fungsi secara berurutan sebagai nilai. Bergantung pada urutan fungsi, hasilnya berubah. Ambil scale
dan translate
. Terkadang berguna untuk mendefinisikan translate
dalam persentase, yang berarti relatif terhadap ukuran elemen. Katakanlah Anda ingin sebuah bola melompat setinggi tiga diameternya sendiri. Sekarang tergantung di mana Anda menempatkan fungsi skala — sebelum atau sesudah translate
— hasilnya berubah dari tiga ketinggian ukuran asli atau yang diskalakan.
Ini adalah sifat penting dari properti transform
. Anda membutuhkannya untuk mencapai transformasi yang cukup kompleks. Tetapi ketika Anda membutuhkan transformasi itu untuk menjadi berbeda dan independen dari transformasi elemen lainnya, itu menghalangi Anda.
Ada kasus ketika Anda tidak dapat menempatkan semua efek dalam satu properti transform
. Itu bisa mendapatkan terlalu banyak cukup cepat. Terutama jika bingkai utama Anda berasal dari tempat yang berbeda, Anda harus memiliki penggabungan yang sangat kompleks dari string yang diubah . Anda hampir tidak dapat mengandalkan mekanisme otomatis karena logikanya tidak mudah. Juga, mungkin sulit untuk memahami apa yang diharapkan. Untuk menyederhanakan ini dan mempertahankan fleksibilitas, kita perlu memisahkannya ke dalam saluran yang berbeda.
Salah satu solusinya adalah dengan membungkus elemen kita ke dalam div
s yang masing-masing dapat dianimasikan secara terpisah, misalnya div untuk pemosisian di kanvas, satu lagi untuk penskalaan, dan yang ketiga untuk rotasi. Dengan begitu, Anda tidak hanya menyederhanakan definisi animasi, Anda juga membuka kemungkinan untuk menentukan asal transformasi yang berbeda jika berlaku.
Tampaknya hal-hal menjadi tidak terkendali dengan trik itu. Bahwa kita mengalikan jumlah masalah yang kita miliki sebelumnya. Sebenarnya, ketika saya pertama kali menemukan trik ini, saya membuangnya karena terlalu banyak. Saya pikir saya bisa memastikan properti transform
saya dikompilasi dari semua bagian dalam urutan yang benar dalam satu bagian. Dibutuhkan satu fungsi transform
lagi untuk membuat hal-hal menjadi terlalu rumit untuk dikelola dan hal-hal tertentu tidak mungkin dilakukan. Kompiler string properti transform
saya mulai membutuhkan lebih banyak waktu untuk memperbaikinya, jadi saya menyerah.
Ternyata mengontrol pemutaran beberapa animasi tidak sesulit kelihatannya pada awalnya. Ingat analogi pemutar kaset dari awal? Bagaimana jika Anda bisa menggunakan pemutar Anda sendiri yang mengambil sejumlah kaset? Lebih dari itu, Anda dapat menambahkan tombol sebanyak yang Anda inginkan pada pemutar itu.
Satu-satunya perbedaan antara memanggil play
pada satu animasi dan serangkaian animasi adalah Anda perlu mengulanginya. Berikut kode yang dapat Anda gunakan untuk metode instance Animation
apa pun:
// To play just call play on all of them animations.forEach((animation) => animation.play());
Kami akan menggunakan ini untuk membuat semua jenis fungsi untuk pemutar kami.
Mari kita buat kotak yang akan menampung animasi dan memainkannya. Anda dapat membuat kotak-kotak itu dengan cara apa pun yang sesuai. Untuk memperjelas, saya akan menunjukkan contoh melakukannya dengan fungsi dan objek. Fungsi createPlayer
mengambil serangkaian animasi yang akan dimainkan secara sinkron. Ini mengembalikan objek dengan metode play
tunggal.
function createPlayer(animations) { return Object.freeze({ play: function () { animations.forEach((animation) => animation.play()); } }); }
Itu cukup untuk Anda ketahui untuk mulai memperluas fungsionalitasnya. Mari tambahkan metode pause dan currentTime
.
function createPlayer(animations) { return Object.freeze({ play: function () { animations.forEach((animation) => animation.play()); }, pause: function () { animations.forEach((animation) => animation.pause()); }, currentTime: function (time = 0) { animations.forEach((animation) => animation.currentTime = time); } }); }
createPlayer
dengan ketiga metode tersebut memberi Anda kontrol yang cukup untuk mengatur sejumlah animasi . Tapi mari kita mendorongnya sedikit lebih jauh. Mari kita buat agar player kita tidak hanya bisa mengambil sejumlah kaset tapi juga player lain.
Seperti yang kita lihat sebelumnya, antarmuka Animation
mirip dengan antarmuka media. Dengan menggunakan kesamaan itu, Anda dapat memasukkan segala macam hal ke dalam pemutar Anda. Untuk mengakomodasi itu, mari kita ubah metode currentTime
untuk membuatnya bekerja dengan objek animasi dan objek yang berasal dari createPlayer
.
function currentTime(time = 0) { animations.forEach(function (animation) { if (typeof animation.currentTime === "function") { animation.currentTime(time); } else { animation.currentTime = time; } }); }
Pemutar yang baru saja kita buat akan memungkinkan Anda menyembunyikan kerumitan beberapa div
untuk saluran animasi elemen tunggal. Elemen-elemen tersebut dapat dikelompokkan dalam sebuah adegan. Dan setiap adegan bisa menjadi bagian dari sesuatu yang lebih besar. Semua itu bisa dilakukan dengan teknik ini.
Untuk mendemonstrasikan demo waktu, saya membagi semua animasi menjadi tiga pemain. Yang pertama adalah mengontrol pemutaran pratinjau di sebelah kanan. Yang kedua menggabungkan animasi melompat dari semua garis bola ke kiri dan yang di pratinjau.
Terakhir, yang ketiga adalah pemain yang menggabungkan animasi posisi bola di wadah kiri. Pemain itu memungkinkan bola menyebar dalam demonstrasi animasi yang berkelanjutan dengan sekitar 60 frame per irisan detik.
Kesimpulan
Antarmuka web seperti Web Animations API memaparkan kepada kami hal-hal tertentu yang dilakukan browser selama ini. Peramban tahu cara merender dengan cepat dengan meneruskan pekerjaan ke GPU. Dengan Web Animations API, kami memiliki kendali atasnya. Meskipun kontrol itu mungkin tampak agak asing atau membingungkan, bukan berarti menggunakannya juga harus membingungkan. Dengan pemahaman tentang pengaturan waktu dan kontrol pemutaran, Anda memiliki alat untuk menyesuaikan API tersebut dengan kebutuhan Anda. Anda harus dapat menentukan seberapa kompleks itu seharusnya.
Bacaan lebih lanjut
- “Teknik Praktis Dalam Merancang Animasi,” Sarah Drasner
- “Mendesain Dengan Gerakan yang Dikurangi Untuk Sensitivitas Gerakan,” Val Head
- “UI Suara Alternatif Untuk Asisten Suara,” Ottomatias Peura
- “Merancang Tooltip yang Lebih Baik Untuk Antarmuka Pengguna Seluler,” Eric Olive