Gerakan adalah bagian inti dari pengalaman digital apa pun, yang memandu pengguna dari satu interaksi ke interaksi berikutnya. Tetapi ada beberapa celah dalam animasi yang halus di platform web. Hal ini mencakup kemampuan untuk menganimasikan animasi masuk dan keluar dengan mudah, serta menganimasikan ke dan dari lapisan atas dengan lancar untuk elemen yang dapat ditutup seperti dialog dan popover.
Untuk mengisi kesenjangan ini, Chrome 116 dan 117 menyertakan empat fitur platform web baru, yang memungkinkan animasi dan transisi yang lancar untuk properti terpisah.
Keempat fitur baru ini mencakup:
- Kemampuan untuk menganimasikan
display
dancontent-visibility
pada linimasa keyframe (Dari Chrome 116). - Properti
transition-behavior
dengan kata kunciallow-discrete
untuk mengaktifkan transisi properti terpisah sepertidisplay
(Dari Chrome 117). - Aturan
@starting-style
untuk menganimasikan efek entri daridisplay: none
dan ke lapisan atas (Dari Chrome 117). - Properti
overlay
untuk mengontrol perilaku lapisan atas selama animasi (Dari Chrome 117).
Menampilkan animasi dalam keyframe
Mulai Chrome 116, Anda dapat menggunakan display
dan content-visibility
dalam aturan keyframe. Kemudian, keduanya akan ditukar pada saat keyframe terjadi. Tidak diperlukan nilai baru tambahan untuk mendukung hal ini:
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
Contoh sebelumnya menganimasikan opasitas ke 0 selama durasi 0,5 detik, lalu menetapkan tampilan ke none. Selain itu, kata kunci forwards
memastikan bahwa animasi tetap berada dalam status akhirnya, sehingga elemen yang diterapkan tetap display: none
dan opacity: 0
.
Ini adalah contoh sederhana yang meniru hal yang dapat Anda lakukan dengan transisi (lihat demo di bagian transisi). Namun, transisi tidak dapat membuat animasi yang lebih kompleks, seperti contoh berikut:
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
Animasi spin-and-delete
adalah animasi keluar. Pertama, kartu akan berputar pada sumbu y, berjalan melalui rotasi hue, lalu pada 80%
melalui linimasa, transisi opasitas dari 1 menjadi 0. Terakhir, kartu akan beralih dari display: block
ke display: none
.
Untuk animasi keluar ini, Anda dapat menyiapkan pemicu untuk animasi, bukan menerapkannya langsung ke elemen. Misalnya, dengan melampirkan pemroses peristiwa ke tombol yang memicu class untuk menerapkan animasi, seperti ini:
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
Contoh di atas kini memiliki status akhir display:none
. Ada banyak kasus saat Anda ingin melakukannya lebih lanjut dan menghapus node DOM dengan waktu tunggu untuk memungkinkan animasi selesai terlebih dahulu.
Melakukan transisi animasi terpisah
Tidak seperti saat menganimasikan properti terpisah dengan keyframe, untuk mentransisikan properti terpisah, Anda harus menggunakan mode perilaku transisi allow-discrete
.
Properti transition-behavior
Mode allow-discrete
adalah faktor yang memungkinkan transisi terpisah, dan merupakan nilai properti transition-behavior
. transition-behavior
menerima dua nilai: normal
dan allow-discrete
.
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
Singkatan transition
juga menetapkan nilai ini, sehingga Anda dapat menghapus properti dan menggunakan kata kunci allow-discrete
di akhir singkatan transition
untuk setiap transisi.
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
Jika menganimasikan beberapa properti terpisah, Anda harus menyertakan allow-discrete
setelah setiap properti yang ingin dianimasikan. Contoh:
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
Aturan @starting-style
untuk animasi entri
Sejauh ini, artikel ini telah membahas animasi keluar. Untuk membuat animasi entri, Anda harus menggunakan aturan @starting-style
.
Gunakan @starting-style
untuk menerapkan gaya yang dapat dicari browser sebelum elemen dibuka di halaman. Ini adalah status “sebelum terbuka” (tempat Anda melakukan animasi).
/* 0. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 1. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
Sekarang Anda memiliki status entri dan keluar untuk item daftar TODO ini:
Menganimasikan elemen ke dan dari lapisan atas
Untuk menganimasikan elemen ke dan dari lapisan atas, tentukan @starting-style
pada status “terbuka” untuk memberi tahu browser tempat animasi akan dimulai. Untuk dialog, status terbuka ditentukan dengan atribut [open]
. Untuk popover, gunakan class semu :popover-open
.
Contoh sederhana dialog dapat terlihat seperti ini:
/* 0. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 1. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
Pada contoh berikutnya, efek masuk dan keluar berbeda. Masuk dengan menganimasikan ke atas dari bagian bawah area pandang, keluar dari efek ke bagian atas area pandang. Kode ini juga ditulis dengan CSS bertingkat untuk enkapsulasi visual yang lebih banyak.
Saat menganimasikan popover, gunakan class pseudo :popover-open
, bukan atribut open
yang digunakan sebelumnya.
.settings-popover {
&:popover-open {
/* 0. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
/* 1. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
Properti overlay
Terakhir, untuk memudarkan popover
atau dialog
dari lapisan atas, tambahkan properti overlay
ke daftar transisi Anda. popover
dan dialog
meng-escape klip dan transformasi ancestor, serta menempatkan konten di lapisan atas. Jika Anda tidak melakukan transisi overlay
, elemen Anda akan segera kembali terpotong, diubah, dan ditutupi, dan Anda tidak akan melihat transisi tersebut terjadi.
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
Sebagai gantinya, sertakan overlay
dalam transisi atau animasi untuk menganimasikan overlay
bersama dengan fitur lainnya dan pastikan overlay
tetap berada di lapisan atas saat menganimasikan. Tampilannya akan terlihat jauh lebih halus.
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
Selain itu, jika Anda memiliki beberapa elemen yang terbuka di lapisan atas, overlay membantu Anda mengontrol transisi yang lancar masuk dan keluar dari lapisan atas. Anda dapat melihat perbedaannya dalam contoh sederhana ini. Jika Anda tidak menerapkan overlay
ke popover kedua saat melakukan transisi, popover tersebut akan keluar dari lapisan atas terlebih dahulu, melompat ke belakang popover lain, sebelum memulai transisi. Efek ini tidak terlalu halus.
Catatan tentang transisi tampilan
Jika Anda melakukan perubahan DOM, seperti menambahkan dan menghapus elemen dari DOM, solusi bagus lainnya untuk animasi yang mulus adalah transisi tampilan. Berikut adalah dua contoh di atas yang dibuat menggunakan transisi tampilan.
Dalam demo pertama ini, alih-alih menyiapkan @starting-style
dan transformasi CSS lainnya, transisi tampilan akan menangani transisi. Transisi tampilan disiapkan seperti ini:
Pertama, di CSS, berikan setiap kartu view-transition-name
individual.
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
Kemudian, dalam JavaScript, gabungkan mutasi DOM (dalam hal ini, menghapus kartu), dalam transisi tampilan.
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
Sekarang, browser dapat menangani memudar dan berubahnya setiap kartu ke posisi barunya.
Contoh lain penggunaan ini adalah dengan demo tambahkan/hapus item daftar. Dalam hal ini, Anda harus ingat untuk menambahkan view-transition-name
unik untuk setiap kartu yang dibuat.
Kesimpulan
Fitur platform baru ini membuat kita selangkah lebih dekat untuk mendapatkan animasi masuk dan keluar yang lancar di platform web. Untuk mempelajari lebih lanjut, lihat tautan berikut: