Hasilkan animasi berbasis gulir yang mulus dan beperforma tinggi dengan CSS murni. Panduan ini membahas animation-timeline dan animation-range untuk kontrol presisi.
CSS Animation Range: Kupas Tuntas Kontrol Animasi Berbasis Gulir
Selama bertahun-tahun, membuat animasi yang bereaksi terhadap posisi gulir pengguna telah menjadi landasan pengalaman web yang menarik. Dari efek fade-in yang halus hingga efek paralaks yang kompleks, interaksi ini menghidupkan halaman statis. Namun, secara tradisional, hal ini datang dengan biaya yang signifikan: ketergantungan pada JavaScript. Pustaka dan skrip kustom yang mendengarkan peristiwa gulir bisa sangat intensif dalam hal performa, berjalan di main thread dan berpotensi menyebabkan pengalaman pengguna yang patah-patah dan tidak responsif, terutama pada perangkat dengan daya lebih rendah.
Masuki era baru animasi web. Kemajuan terbaru dalam CSS merevolusi cara kita menangani interaksi ini. Spesifikasi Scroll-Driven Animations menyediakan cara yang kuat, deklaratif, dan sangat beperforma tinggi untuk menautkan animasi langsung ke posisi bilah gulir atau visibilitas elemen di dalam viewport—semuanya tanpa satu baris pun JavaScript.
Inti dari paradigma baru ini adalah dua properti kunci: animation-timeline dan animation-range. Meskipun animation-timeline mengatur panggung dengan mendefinisikan apa yang menggerakkan animasi (misalnya, bilah gulir dokumen), animation-range-lah yang memberi kita kontrol granular yang selalu kita dambakan. Properti ini memungkinkan kita untuk mendefinisikan titik awal dan akhir yang presisi dari sebuah animasi dalam linimasa tersebut.
Dalam panduan komprehensif ini, kita akan menjelajahi dunia Animasi Berbasis Gulir CSS dengan fokus khusus pada animation-range. Kita akan membahas:
- Konsep dasar Linimasa Progres Gulir (Scroll) dan Tampilan (View).
- Penjelasan rinci tentang properti
animation-rangedan sintaksnya. - Contoh praktis dari dunia nyata untuk membuat bilah progres, efek kemunculan, dan lainnya.
- Praktik terbaik untuk performa, aksesibilitas, dan kompatibilitas browser.
Bersiaplah untuk membuka potensi animasi yang tidak hanya indah tetapi juga sangat efisien, memindahkan logika kompleks dari main thread ke compositor thread untuk pengalaman yang dijamin sangat mulus.
Memahami Fondasi: Apa itu Animasi Berbasis Gulir?
Sebelum kita menyelami animation-range, sangat penting untuk memahami sistem di mana ia beroperasi. Secara tradisional, animasi CSS terikat pada linimasa berbasis waktu. Ketika Anda mendefinisikan animation-duration: 3s;, animasi berjalan dari 0% hingga 100% selama tiga detik, didorong oleh jam.
Animasi Berbasis Gulir secara fundamental mengubah ini. Mereka memperkenalkan konsep Linimasa Progres, yang tidak didorong oleh waktu, tetapi oleh progres—baik progres menggulir sebuah wadah atau progres visibilitas sebuah elemen saat bergerak melalui viewport.
Model baru ini menawarkan tiga keuntungan utama:
- Performa: Karena animasi ini dapat dijalankan di luar main thread pada compositor thread browser, mereka tidak bersaing untuk sumber daya dengan JavaScript, operasi layout, atau paint. Hasilnya adalah animasi yang sangat mulus, bebas dari 'jank' yang sering mengganggu pendengar gulir berbasis JS.
- Kesederhanaan: Sintaks CSS bersifat deklaratif. Anda menyatakan apa yang Anda ingin terjadi, dan browser menangani perhitungan yang kompleks. Ini sering kali menghasilkan kode yang lebih bersih dan lebih mudah dipelihara dibandingkan dengan JavaScript imperatif.
- Aksesibilitas: Animasi ini menghormati preferensi pengguna seperti
prefers-reduced-motionsecara otomatis, membuatnya lebih mudah untuk membangun pengalaman yang inklusif.
Ada dua jenis utama linimasa progres yang akan Anda gunakan:
- Linimasa Progres Gulir (Scroll Progress Timeline): Melacak posisi gulir di dalam sebuah wadah gulir ("scroller"). Linimasa ini merepresentasikan seluruh rentang yang dapat digulir, dari paling atas (0%) hingga paling bawah (100%).
- Linimasa Progres Tampilan (View Progress Timeline): Melacak visibilitas sebuah elemen saat melintasi viewport. Linimasa ini merepresentasikan perjalanan elemen dari saat baru memasuki viewport hingga benar-benar keluar darinya.
Konsep Inti: Properti animation-timeline
Langkah pertama dalam membuat animasi berbasis gulir adalah melepaskan animasi CSS standar dari jam berbasis waktu default-nya dan menempelkannya ke linimasa berbasis progres yang baru. Ini dilakukan menggunakan properti animation-timeline.
Properti ini menerima sebuah fungsi yang mendefinisikan sumber linimasa: baik scroll() untuk Linimasa Progres Gulir atau view() untuk Linimasa Progres Tampilan.
Linimasa Progres Gulir: scroll()
Fungsi scroll() mengikat animasi ke posisi gulir sebuah wadah. Bentuknya yang paling umum adalah scroll(scroller, axis).
scroller: Menentukan elemen gulir mana yang akan dilacak. Bisa beruparoot(viewport dokumen),self(elemen itu sendiri, jika merupakan scroller), ataunearest(scroller leluhur terdekat).axis: Menentukan sumbu gulir yang akan dilacak. Bisa berupablock(arah utama aliran konten, biasanya vertikal),inline(tegak lurus terhadap block, biasanya horizontal),y, ataux.
Contoh: Bilah Progres Gulir Dokumen Sederhana
Mari kita membuat bilah progres di bagian atas halaman yang memanjang saat pengguna menggulir ke bawah.
<!-- HTML -->
<div id="progress-bar"></div>
<!-- CSS -->
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
#progress-bar {
position: fixed;
top: 0;
left: 0;
height: 10px;
width: 100%;
background-color: dodgerblue;
transform-origin: left;
/* Lepaskan dari waktu, kaitkan ke gulir dokumen */
animation: grow-progress linear;
animation-timeline: scroll(root block);
}
Dalam contoh ini, animasi grow-progress sekarang digerakkan oleh pengguliran dokumen utama (root) pada sumbu vertikalnya (block). Saat Anda menggulir dari 0% hingga 100% halaman, transformasi scaleX bilah progres berubah dari 0 menjadi 1.
Linimasa Progres Tampilan: view()
Fungsi view() mengikat animasi ke visibilitas elemen di dalam scrollernya. Ini sangat berguna untuk memicu animasi "kemunculan" saat elemen masuk ke dalam tampilan.
Sintaksnya adalah view(axis, inset).
axis: Opsional, nilai yang sama seperti discroll()(mis.,block). Mendefinisikan sumbu scrollport mana yang akan dipertimbangkan.inset: Opsional, memungkinkan Anda menyesuaikan batas-batas viewport yang digunakan untuk menghitung visibilitas, mirip denganrootMarginpadaIntersectionObserver.
Contoh: Memudarkan Elemen Masuk
<!-- HTML -->
<div class="content-box reveal">
Kotak ini akan memudar masuk saat memasuki layar.
</div>
<!-- CSS -->
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.reveal {
/* Kaitkan animasi ke visibilitas elemen ini */
animation: fade-in linear;
animation-timeline: view();
}
Di sini, animasi fade-in ditautkan ke elemen .reveal itu sendiri. Animasi akan berlanjut seiring elemen tersebut bergerak melintasi viewport. Tapi bagaimana tepatnya pemetaannya? Kapan animasi itu dimulai dan berakhir? Di situlah animation-range berperan.
Bintang Utamanya: animation-range
Meskipun animation-timeline mengatur konteksnya, animation-range menyediakan kontrol yang krusial. Properti ini mendefinisikan bagian mana dari linimasa yang dianggap "aktif" dan memetakannya ke progres 0% hingga 100% dari animasi @keyframes Anda.
Sintaks dasarnya adalah:
animation-range: <range-start> <range-end>;
Ini memberi tahu browser: "Ketika linimasa mencapai titik <range-start>, animasi harus berada di 0%. Ketika mencapai titik <range-end>, animasi harus berada di 100%."
Nilai untuk <range-start> dan <range-end> bisa berupa salah satu dari beberapa jenis:
- Kata Kunci (untuk
view()): Nama-nama khusus yang sangat intuitif sepertientry,exit,cover, dancontain. Kita akan menjelajahi ini secara detail. - Persentase: Persentase dari total durasi linimasa. Untuk linimasa
scroll(),0%adalah bagian atas dan100%adalah bagian bawah. - Panjang CSS: Nilai panjang tetap seperti
100pxatau20rem. Ini menentukan titik pada offset gulir tersebut dari awal linimasa.
Anda bahkan dapat menggabungkan kata kunci dengan persentase atau panjang untuk kontrol yang sangat halus, seperti entry 50% atau cover 200px.
Kupas Tuntas Praktis: animation-range dengan Linimasa scroll()
Saat bekerja dengan linimasa scroll(), Anda memetakan animasi Anda ke rentang gulir keseluruhan dari scroller. Mari kita lihat bagaimana animation-range membantu kita menargetkan bagian-bagian tertentu dari perjalanan itu.
Menargetkan Bagian Gulir Tertentu
Bayangkan Anda memiliki artikel panjang dan Anda ingin grafik tertentu beranimasi hanya saat pengguna menggulir melalui separuh bagian tengah halaman.
@keyframes spin-and-grow {
from { transform: rotate(0deg) scale(0.5); opacity: 0; }
to { transform: rotate(360deg) scale(1); opacity: 1; }
}
.special-graphic {
animation: spin-and-grow linear;
animation-timeline: scroll(root block);
/* Animasi dimulai pada 25% guliran dan berakhir pada 75% guliran */
animation-range: 25% 75%;
}
Cara kerjanya:
- Sebelum pengguna menggulir 25% dari halaman, animasi ditahan pada keadaan 0% (
rotate(0deg) scale(0.5) opacity: 0). - Saat pengguna menggulir dari tanda 25% ke tanda 75%, animasi berlanjut dari 0% hingga 100%.
- Setelah pengguna menggulir melewati tanda 75%, animasi ditahan pada keadaan 100% (
rotate(360deg) scale(1) opacity: 1).
Penambahan sederhana animation-range ini memberi kita kontrol yang kuat atas waktu dan penempatan efek kita dalam pengalaman gulir yang lebih besar.
Menggunakan Panjang Absolut
Anda juga dapat menggunakan panjang absolut. Misalnya, jika Anda ingin animasi terjadi hanya selama 500 piksel pertama pengguliran:
.hero-animation {
animation: fade-out linear;
animation-timeline: scroll(root block);
/* Animasi dimulai pada offset gulir 0px dan berakhir pada 500px */
animation-range: 0px 500px;
}
Ini sempurna untuk animasi pengantar di bagian hero halaman yang harus selesai setelah pengguna mulai menggulir lebih dalam ke konten.
Menguasai animation-range dengan Linimasa view()
Di sinilah animation-range menjadi benar-benar ajaib. Ketika digunakan dengan linimasa view(), nilai rentang tidak didasarkan pada tinggi gulir seluruh dokumen, tetapi pada visibilitas elemen di dalam viewport. Di sinilah rentang bernama khusus berperan.
Penjelasan Rentang Bernama
Bayangkan sebuah elemen ("subjek") dan viewport ("scroller"). Rentang bernama ini menggambarkan hubungan antara kedua kotak ini.
entry: Fase di mana subjek sedang memasuki viewport. Dimulai saat tepi bawah subjek melintasi tepi atas viewport dan berakhir saat tepi bawah subjek melintasi tepi bawah viewport.exit: Fase di mana subjek sedang meninggalkan viewport. Dimulai saat tepi atas subjek melintasi tepi atas viewport dan berakhir saat tepi atas subjek melintasi tepi bawah viewport.cover: Fase di mana subjek cukup besar untuk menutupi viewport sepenuhnya. Dimulai saat tepi atas subjek mengenai tepi atas viewport dan berakhir saat tepi bawah subjek mengenai tepi bawah viewport. Jika subjek lebih kecil dari viewport, fase ini tidak pernah terjadi.contain: Fase di mana subjek sepenuhnya termuat di dalam viewport. Dimulai saat tepi bawah subjek memasuki tepi bawah viewport dan berakhir saat tepi atas subjek keluar dari tepi atas viewport. Jika subjek lebih besar dari viewport, fase ini tidak pernah terjadi.
Contoh Praktis: Efek Klasik "Muncul Saat Digulir"
Mari kita buat ulang salah satu animasi berbasis gulir yang paling umum: sebuah elemen yang memudar dan meluncur ke dalam tampilan saat memasuki layar. Secara tradisional, ini memerlukan Intersection Observer di JavaScript. Sekarang, hanya perlu beberapa baris CSS.
<!-- HTML -->
<section>
<div class="content-box reveal">Box 1</div>
<div class="content-box reveal">Box 2</div>
<div class="content-box reveal">Box 3</div>
</section>
<!-- CSS -->
@keyframes fade-and-slide-in {
from { opacity: 0; transform: translateY(50px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-and-slide-in linear both; /* 'both' itu penting! */
animation-timeline: view();
/* Mulai animasi saat elemen masuk, akhiri saat separuh jalan masuk */
animation-range: entry 0% entry 50%;
}
Mari kita bedah nilai animation-range tersebut:
animation-fill-mode: both;sangat penting. Ini memastikan bahwa sebelum rentang aktif animasi, elemen tetap pada keadaanfrom-nya (tidak terlihat dan bergeser ke bawah), dan setelah rentang tersebut, ia tetap pada keadaanto-nya (terlihat sepenuhnya dan di tempatnya).entry 0%: Titik awal. Ini mengacu pada awal dari faseentry—saat yang tepat di mana bagian bawah elemen kita menyentuh bagian bawah viewport.entry 50%: Titik akhir. Ini mengacu pada saat elemen telah menyelesaikan 50% perjalanannya melalui faseentry. Pada titik ini, animasi akan 100% selesai.
Ini memberikan efek yang menyenangkan di mana item tersebut sepenuhnya terlihat dan berada di posisi akhirnya jauh sebelum pengguna menggulirnya ke tengah layar. Anda dapat menyesuaikan persentase ini untuk mendapatkan nuansa yang Anda inginkan. Misalnya, entry 25% entry 75% akan menciptakan animasi yang lebih panjang.
Kontrol Lanjutan: Membuat Efek Paralaks
Mari kita coba efek yang lebih kompleks. Kita akan membuat gambar latar belakang bergerak dengan kecepatan yang berbeda dari guliran, tetapi hanya saat wadahnya menutupi viewport.
<!-- HTML -->
<div class="parallax-container">
<div class="parallax-bg"></div>
<h2>Bagian Paralaks</h2>
</div>
<!-- CSS -->
@keyframes parallax-shift {
from { background-position: 50% -50px; }
to { background-position: 50% 50px; }
}
.parallax-container {
position: relative;
height: 100vh;
overflow: hidden;
}
.parallax-bg {
position: absolute;
inset: -50px; /* Buat lebih tinggi dari kontainer untuk memungkinkan pergerakan */
background-image: url('your-image.jpg');
background-size: cover;
animation: parallax-shift linear both;
animation-timeline: view(block);
/* Animasikan di seluruh fase 'cover' */
animation-range: cover 0% cover 100%;
}
Dalam kasus ini, animasi parallax-shift terkait dengan linimasa elemen parallax-bg. animation-range diatur ke durasi penuh dari fase cover. Ini berarti animasi mulai berjalan hanya ketika wadah cukup tinggi untuk menutupi viewport dan diposisikan sedemikian rupa sehingga bagian atasnya berada di bagian atas viewport. Animasi selesai ketika bagian bawah wadah mencapai bagian bawah viewport. Hasilnya adalah efek paralaks yang mulus dan beperforma tinggi yang tersinkronisasi sempurna dengan posisi gulir.
Menggabungkan Semuanya: Shorthand dan Praktik Terbaik
Shorthand animation
Untuk membuat sintaks lebih ringkas, properti linimasa dan rentang dapat dimasukkan langsung ke dalam properti shorthand animation. Ini adalah sintaks baru yang diusulkan dan sedang mendapatkan dukungan.
Contoh kemunculan-saat-gulir kita dapat ditulis ulang sebagai:
.reveal {
animation: fade-and-slide-in linear both view() entry 0% entry 50%;
}
Satu baris ini menggantikan tiga properti terpisah: animation, animation-timeline, dan animation-range. Ini bersih, efisien, dan menyimpan semua logika animasi di satu tempat.
Pertimbangan Performa
Manfaat utama dari animasi berbasis gulir adalah performa. Untuk mempertahankan manfaat ini, Anda harus memprioritaskan menganimasikan properti yang dapat ditangani oleh compositor thread. Properti-properti ini utamanya adalah:
transform(translate, scale, rotate)opacity
Menganimasikan properti seperti width, height, margin, atau color akan tetap berfungsi, tetapi mereka mungkin memicu operasi layout dan paint, yang terjadi di main thread. Meskipun sering kali masih lebih mulus daripada alternatif berbasis JS, mereka tidak akan se-performa animasi yang hanya menggunakan compositor.
Aksesibilitas dan Fallback
Sangat penting untuk membangun untuk semua pengguna. Animasi berbasis gulir memang bagus, tetapi beberapa pengguna merasa gerakan mengganggu atau memualkan.
1. Hormati Preferensi Pengguna: Selalu bungkus CSS terkait gerakan Anda dalam media query prefers-reduced-motion.
@media (prefers-reduced-motion: no-preference) {
.reveal {
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
2. Sediakan Fallback untuk Browser Lama: Karena ini adalah teknologi baru, Anda harus memperhitungkan browser yang belum mendukungnya. Aturan @supports adalah teman terbaik Anda di sini. Sediakan keadaan default yang sederhana dan non-animasi, lalu tingkatkan untuk browser yang mendukung.
/* Keadaan default untuk semua browser */
.reveal {
opacity: 1;
transform: translateY(0);
}
/* Peningkatan untuk browser yang mendukung */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0; /* Atur keadaan awal untuk animasi */
transform: translateY(50px);
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
}
Dukungan Browser dan Pandangan ke Depan
Hingga akhir 2023, Animasi Berbasis Gulir CSS didukung di Chrome dan Edge. Fitur ini sedang dalam pengembangan aktif di Firefox dan sedang dipertimbangkan oleh Safari. Seperti halnya fitur platform web mutakhir lainnya, penting untuk memeriksa sumber daya seperti CanIUse.com untuk informasi dukungan terbaru.
Pengenalan teknologi ini menandai pergeseran signifikan dalam pengembangan web. Ini memberdayakan desainer dan pengembang untuk menciptakan pengalaman yang kaya, interaktif, dan beperforma tinggi secara deklaratif, mengurangi ketergantungan kita pada JavaScript untuk seluruh kelas pola UI yang umum. Seiring matangnya dukungan browser, harapkan animasi berbasis gulir menjadi alat penting dalam perangkat setiap pengembang front-end.
Kesimpulan
Animasi Berbasis Gulir CSS, dan khususnya properti animation-range, merepresentasikan lompatan monumental ke depan untuk animasi web. Kita telah beralih dari linimasa berbasis waktu ke linimasa berbasis progres, membuka kemampuan untuk menciptakan interaksi yang kompleks dan sadar-gulir dengan performa dan kesederhanaan yang tak tertandingi.
Kita telah belajar bahwa:
animation-timelinemenautkan animasi ke linimasa progresscroll()atauview().animation-rangememberi kita kontrol presisi, memetakan bagian spesifik dari linimasa tersebut ke keyframe animasi kita.- Dengan linimasa
view(), rentang bernama yang kuat sepertientry,exit,cover, dancontainmenyediakan cara intuitif untuk mengontrol animasi berdasarkan visibilitas elemen. - Dengan tetap menggunakan properti yang ramah-compositor dan menyediakan fallback, kita dapat menggunakan teknologi ini hari ini untuk membangun pengalaman pengguna yang dapat diakses, beperforma tinggi, dan menyenangkan.
Hari-hari di mana kita harus berjuang dengan scroll listener yang patah-patah dan memblokir main thread untuk efek sederhana sudah terhitung. Masa depan animasi berbasis gulir ada di sini, bersifat deklaratif, dan ditulis dalam CSS. Inilah saatnya untuk mulai bereksperimen.