Wolfenstein khusus CSS adalah proyek kecil yang saya buat beberapa minggu yang lalu. Itu adalah eksperimen dengan transformasi dan animasi 3D CSS.
Terinspirasi oleh demo FPS dan lain Wolfenstein Code Pen, saya memutuskan untuk membuat versi saya sendiri. Ini secara longgar didasarkan pada Episode 1 โ Lantai 9 dari game 3D Wolfenstein asli.
Editor: Game ini sengaja membutuhkan reaksi cepat untuk menghindari layar Game Over.
Berikut adalah video pemutarannya:
Singkatnya, proyek saya tidak lain adalah animasi CSS panjang yang ditulis dengan hati-hati. Ditambah beberapa contoh dari peretasan kotak centang.
:checked ~ div { animation-name: spin; }
Lingkungan terdiri dari wajah kisi 3D dan animasinya sebagian besar adalah terjemahan dan rotasi 3D biasa. Tidak ada yang benar-benar mewah.
Namun, dua masalah sangat sulit untuk dipecahkan:
- Mainkan animasi "penembakan senjata" setiap kali pemain mengklik musuh.
- Saat bos yang bergerak cepat mendapat pukulan terakhir, masukkan gerakan lambat yang dramatis.
Pada tingkat teknis, ini berarti:
- Putar ulang animasi saat kotak centang berikutnya dicentang.
- Memperlambat animasi, saat kotak centang dicentang.
Faktanya, tidak ada yang diselesaikan dengan benar dalam proyek saya! Saya akhirnya menggunakan solusi atau menyerah begitu saja.
Di sisi lain, setelah beberapa penggalian, akhirnya saya menemukan kunci untuk kedua masalah: mengubah properti menjalankan animasi CSS. Pada artikel ini, kita akan mengeksplorasi lebih lanjut tentang topik ini:
- Banyak contoh interaktif.
- Dissections: bagaimana setiap contoh bekerja (atau tidak bekerja)?
- Di balik layar: bagaimana browser menangani status animasi?
Ijinkan aku โlemparkan batu bata sayaโ.
Masalah 1: Memutar Ulang Animasi
Contoh pertama: "hanya kotak centang lain"
Intuisi pertama saya adalah "tambahkan saja kotak centang lain", yang tidak berfungsi:
Setiap kotak centang berfungsi secara individual, tetapi tidak keduanya bersama-sama. Jika satu kotak centang sudah dicentang, yang lain tidak lagi berfungsi.
Begini cara kerjanya (atau "tidak berfungsi"):
- Grafik
animation-name
of<div>
isnone
secara default - Pengguna mengklik satu kotak centang,
animation-name
menjadispin
, dan animasi dimulai dari awal. - Setelah beberapa saat, pengguna mengklik kotak centang lainnya. Aturan CSS baru berlaku, tapi
animation-name
is masihspin
, yang berarti tidak ada animasi yang ditambahkan atau dihapus. Animasi terus diputar seolah-olah tidak ada yang terjadi.
Contoh kedua: "mengkloning animasi"
Salah satu pendekatan yang berfungsi adalah mengkloning animasi:
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }
Berikut adalah cara kerjanya:
animation-name
isnone
mulanya.- Pengguna mengklik "Putar!",
animation-name
menjadispin1
. Animasispin1
dimulai dari awal karena baru saja ditambahkan. - Pengguna mengklik "Putar lagi!",
animation-name
menjadispin2
. Animasispin2
dimulai dari awal karena baru saja ditambahkan.
Perhatikan bahwa pada Langkah #3, spin1
dihapus karena urutan aturan CSS. Ini tidak akan bekerja jika "Putar lagi!" diperiksa terlebih dahulu.
Contoh ketiga: "menambahkan animasi yang sama"
Pendekatan kerja lainnya adalah "menambahkan animasi yang sama":
#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }
Ini mirip dengan contoh sebelumnya. Anda sebenarnya dapat memahami perilaku dengan cara ini:
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }
Perhatikan bahwa ketika โPutar lagi!โ dicentang, animasi lama yang berjalan menjadi animasi kedua dalam daftar baru, yang mungkin tidak intuitif. Konsekuensi langsungnya adalah: triknya tidak akan berhasil jika animation-fill-mode
is forwards
. Berikut demonya:
Jika Anda bertanya-tanya mengapa hal ini terjadi, berikut adalah beberapa petunjuknya:
animation-fill-mode
isnone
secara default, yang berarti "Animasi tidak berpengaruh sama sekali jika tidak diputar".animation-fill-mode: forwards;
berarti "Setelah animasi selesai diputar, itu harus tetap berada di keyframe terakhir selamanya".spin1
keputusannya selalu ditimpaspin2
karenaspin1
muncul kemudian dalam daftar.- Misalkan pengguna mengklik "Putar!", menunggu putaran penuh, lalu mengklik "Putar lagi!". Saat ini.
spin1
sudah selesai, danspin2
baru saja dimulai.
Diskusi
Aturan praktis: Anda tidak dapat "memulai ulang" animasi CSS yang ada. Sebagai gantinya, Anda ingin menambahkan dan memainkan animasi baru. Ini dapat dikonfirmasi oleh spesifikasi W3C:
Setelah animasi dimulai, itu berlanjut hingga berakhir atau nama animasi dihapus.
Sekarang membandingkan dua contoh terakhir, saya pikir dalam praktiknya, "animasi kloning" seharusnya sering bekerja lebih baik, terutama ketika praprosesor CSS tersedia.
Masalah 2: Gerakan Lambat
Orang mungkin berpikir bahwa memperlambat animasi hanyalah masalah pengaturan yang lebih lama animation-duration
:
div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }
Memang, ini berfungsi:
โฆ atau apakah itu?
Dengan beberapa penyesuaian, seharusnya lebih mudah untuk melihat masalahnya.
Ya, animasinya melambat. Dan tidak, itu tidak terlihat bagus. Anjing (hampir) selalu "melompat" saat Anda mengaktifkan kotak centang. Selain itu, anjing tampaknya melompat ke posisi acak daripada yang awal. Bagaimana bisa?
Akan lebih mudah untuk memahaminya jika kita memperkenalkan dua "elemen bayangan":
Kedua elemen bayangan menjalankan animasi yang sama dengan yang berbeda animation-duration
. Dan mereka tidak terpengaruh oleh kotak centang.
Saat Anda mengaktifkan kotak centang, elemen segera beralih di antara status dua elemen bayangan.
Mengutip spesifikasi W3C:
Perubahan pada nilai properti animasi saat animasi berjalan berlaku seolah-olah animasi memiliki nilai tersebut sejak dimulai.
Ini mengikuti tanpa kewarganegaraan design, yang memungkinkan browser menentukan nilai animasi dengan mudah. Perhitungan sebenarnya dijelaskan di sini dan di sini.
Upaya lain
Satu ide adalah untuk menjeda animasi saat ini, lalu menambahkan animasi lebih lambat yang mengambil alih dari sana:
div {
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
Jadi ini berfungsi:
โฆ atau apakah itu?
Itu melambat ketika Anda mengklik "Slowmo!". Tetapi jika Anda menunggu satu lingkaran penuh, Anda akan melihat "lompatan". Sebenarnya, selalu melompat ke posisi ketika "Slowmo!" diklik.
Alasannya adalah kami tidak memiliki from
keyframe didefinisikan โ dan kita seharusnya tidak melakukannya. Ketika pengguna mengklik "Slowmo!", spin1
dijeda di beberapa posisi, dan spin2
dimulai pada posisi yang sama persis. Kita tidak bisa memprediksi posisi itu sebelumnya โฆ atau bisakah kita?
Solusi yang Bekerja
Kita dapat! Dengan menggunakan properti kustom, kita dapat menangkap sudut di animasi pertama, lalu meneruskannya ke animasi kedua:
div {
transform: rotate(var(--angle1));
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
transform: rotate(var(--angle2));
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
@keyframes spin1 {
to {
--angle1: 360deg;
}
}
@keyframes spin2 {
from {
--angle2: var(--angle1);
}
to {
--angle2: calc(var(--angle1) + 360deg);
}
}
Catatan: @property
digunakan dalam contoh ini, yaitu tidak didukung oleh semua browser.
Solusi "Sempurna"
Ada peringatan untuk solusi sebelumnya: "keluar dari slowmo" tidak berfungsi dengan baik.
Inilah solusi yang lebih baik:
Dalam versi ini, gerakan lambat dapat masuk atau keluar dengan mulus. Tidak ada fitur eksperimental yang digunakan. Jadi apakah itu solusi yang tepat? Iya dan tidak.
Solusi ini berfungsi seperti "menggeser" "roda gigi":
- Roda gigi: ada dua
<div>
s. Yang satu adalah orang tua dari yang lain. Keduanya memilikispin
animasi tetapi dengan berbedaanimation-duration
. Status terakhir dari elemen adalah akumulasi dari kedua animasi. - Pergeseran: Pada awalnya, hanya satu
<div>
menjalankan animasinya. Yang lainnya dijeda. Saat kotak centang diaktifkan, kedua animasi menukar statusnya.
Meskipun saya sangat menyukai hasilnya, ada satu masalah: ini adalah eksploitasi yang bagus dari spin
animasi, yang tidak berfungsi untuk jenis animasi lain pada umumnya.
Solusi Praktis (dengan JS)
Untuk animasi umum, dimungkinkan untuk mencapai fungsi gerakan lambat dengan sedikit JavaScript:
Penjelasan singkat:
- Properti kustom digunakan untuk melacak kemajuan animasi.
- Animasi "dimulai ulang" ketika kotak centang diaktifkan.
- Kode JS menghitung yang benar
animation-delay
untuk memastikan transisi yang mulus. saya merekomendasi artikel ini jika Anda tidak terbiasa dengan nilai negatif darianimation-delay
.
Anda dapat melihat solusi ini sebagai campuran dari "menghidupkan ulang animasi" dan pendekatan "penggeseran gigi".
Di sini penting untuk melacak kemajuan animasi dengan benar. Solusi dapat dilakukan jika @property
tidak tersedia. Sebagai contoh, versi ini menggunakan z-index
untuk melacak kemajuan:
Catatan samping: awalnya, saya juga mencoba membuat versi khusus CSS tetapi tidak berhasil. Meskipun tidak 100% yakin, saya pikir itu karena animation-delay
is tidak bisa dianimasikan.
Ini adalah versi dengan JavaScript minimal. Hanya "memasuki slowmo" yang berfungsi.
Beri tahu saya jika Anda berhasil membuat versi khusus CSS yang berfungsi!
Slow-mo Any Animation (dengan JS)
Terakhir, saya ingin membagikan solusi yang berfungsi untuk (hampir) animasi apa pun, bahkan dengan banyak yang rumit @keyframes
:
Pada dasarnya, Anda perlu menambahkan pelacak kemajuan animasi, lalu hitung dengan cermat animation-delay
untuk animasi baru. Namun, terkadang sulit (tetapi mungkin) untuk mendapatkan nilai yang benar.
Sebagai contoh:
animation-timing-function
tidaklinear
.animation-direction
tidaknormal
.- beberapa nilai dalam
animation-name
dengan berbedaanimation-duration
dananimation-delay
'S.
Metode ini juga dijelaskan di sini untuk API Animasi Web.
Ucapan Terima Kasih
Saya memulai jalan ini setelah menemukan proyek khusus CSS. Beberapa adalah karya seni yang halus, dan beberapa adalah alat yang rumit. Favorit saya adalah yang melibatkan objek 3D, misalnya, ini bola memantul dan ini kubus pengepakan.
Pada awalnya, saya tidak tahu bagaimana ini dibuat. Kemudian saya membaca dan belajar banyak dari tutorial bagus ini oleh Ana Tudor.
Ternyata, membangun dan menganimasikan objek 3D dengan CSS tidak jauh berbeda dengan melakukannya dengan Pencampur, hanya dengan rasa yang sedikit berbeda.
Kesimpulan
Dalam artikel ini kami memeriksa perilaku animasi CSS saat animate-*
properti diubah. Terutama kami menemukan solusi untuk "memutar ulang animasi" dan "animasi slow-mo".
Saya harap Anda menemukan artikel ini menarik. Ceritakan apa yang sedang kau pikirkan!