Meningkatkan Aliran Pengguna Melalui Transisi Halaman

Diterbitkan: 2022-03-10
Ringkasan cepat Setiap kali pengalaman pengguna terganggu, kemungkinan mereka pergi meningkat. Mengubah dari satu halaman ke halaman lain akan sering menyebabkan gangguan ini dengan menunjukkan kilatan putih tanpa konten, dengan terlalu lama memuat, atau dengan cara lain membawa pengguna keluar dari konteks sebelum halaman baru dibuka.

Transisi antar halaman dapat meningkatkan pengalaman dengan mempertahankan (atau bahkan meningkatkan) konteks pengguna, mempertahankan perhatian mereka, dan memberikan kontinuitas visual dan umpan balik positif. Pada saat yang sama, transisi halaman juga dapat menyenangkan dan estetis dan dapat memperkuat branding jika dilakukan dengan baik.

Page Transitions

Dalam artikel ini, kami akan membuat, langkah demi langkah, transisi antar halaman. Kami juga akan berbicara tentang pro dan kontra dari teknik ini dan bagaimana mendorongnya hingga batasnya.

Contoh

Banyak aplikasi seluler memanfaatkan transisi antar tampilan dengan baik. Pada contoh di bawah, yang mengikuti pedoman desain material Google, kita melihat bagaimana animasi menyampaikan hubungan hierarkis dan spasial antar halaman.

Mengapa kami tidak menggunakan pendekatan yang sama dengan situs web kami? Mengapa kami setuju dengan pengguna yang merasa seperti sedang diteleportasi setiap kali halaman berubah?

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Cara Transisi Antar Halaman Web

Kerangka SPA

Sebelum membuat tangan kita kotor, saya harus mengatakan sesuatu tentang kerangka kerja aplikasi satu halaman (SPA). Jika Anda menggunakan kerangka SPA (seperti AngularJS, Backbone.js atau Ember), maka membuat transisi antar halaman akan jauh lebih mudah karena semua perutean sudah ditangani oleh JavaScript. Silakan merujuk ke dokumentasi yang relevan untuk melihat cara mentransisikan halaman menggunakan kerangka pilihan Anda, karena mungkin ada beberapa contoh dan tutorial yang bagus.

Jalan yang salah

Upaya pertama saya untuk membuat transisi antar halaman terlihat kurang lebih seperti ini:

 document.addEventListener('DOMContentLoaded', function() { // Animate in }); document.addEventListener('beforeunload', function() { // Animate out });

Konsepnya sederhana: Gunakan satu animasi saat pengguna meninggalkan halaman, dan animasi lain saat halaman baru dimuat.

Namun, saya segera menemukan bahwa solusi ini memiliki beberapa keterbatasan:

  • Kami tidak tahu berapa lama halaman berikutnya akan dimuat, jadi animasinya mungkin tidak terlihat lancar.
  • Kami tidak dapat membuat transisi yang menggabungkan konten dari halaman sebelumnya dan halaman berikutnya.

Faktanya, satu-satunya cara untuk mencapai transisi yang lancar dan mulus adalah dengan memiliki kontrol penuh atas proses perubahan halaman dan, oleh karena itu, tidak mengubah halaman sama sekali . Jadi, kita harus mengubah pendekatan kita terhadap masalah.

Jalan yang benar

Mari kita lihat langkah-langkah yang terlibat dalam membuat transisi crossfade sederhana antar halaman dengan cara yang benar. Ini melibatkan sesuatu yang disebut pushState AJAX (atau PJAX), yang pada dasarnya akan mengubah situs web kita menjadi semacam situs web satu halaman.

Teknik ini tidak hanya mencapai transisi yang mulus dan menyenangkan, tetapi kita akan mendapat manfaat dari keuntungan lain, yang akan kita bahas secara rinci nanti di artikel ini.

Cegah Perilaku Tautan Default

Langkah pertama adalah membuat event listener click untuk digunakan semua tautan, mencegah browser melakukan perilaku defaultnya dan menyesuaikan cara menangani perubahan halaman.

 // Note, we are purposely binding our listener on the document object // so that we can intercept any anchors added in future. document.addEventListener('click', function(e) { var el = e.target; // Go up in the nodelist until we find a node with .href (HTMLAnchorElement) while (el && !el.href) { el = el.parentNode; } if (el) { e.preventDefault(); return; } });

Metode penambahan pendengar acara ke elemen induk, alih-alih menambahkannya ke setiap simpul tertentu, disebut delegasi acara, dan ini dimungkinkan karena sifat gelembung peristiwa dari HTML DOM API.

Ambil Halamannya

Sekarang kita telah menginterupsi browser ketika mencoba mengubah halaman, kita dapat mengambil halaman itu secara manual menggunakan Fetch API. Mari kita lihat fungsi berikut, yang mengambil konten HTML dari sebuah halaman ketika diberikan URL-nya.

 function loadPage(url) { return fetch(url, { method: 'GET' }).then(function(response) { return response.text(); }); }

Untuk browser yang tidak mendukung Fetch API, pertimbangkan untuk menambahkan polyfill atau menggunakan XMLHttpRequest kuno yang bagus.

Ubah URL Saat Ini

HTML5 memiliki API fantastis yang disebut pushState , yang memungkinkan situs web mengakses dan mengubah riwayat peramban tanpa memuat laman apa pun. Di bawah ini, kami menggunakannya untuk mengubah URL saat ini menjadi URL halaman berikutnya. Perhatikan bahwa ini adalah modifikasi dari penangan peristiwa klik jangkar yang kami nyatakan sebelumnya.

 if (el) { e.preventDefault(); history.pushState(null, null, el.href); changePage(); return; }

Seperti yang mungkin Anda perhatikan, kami juga telah menambahkan panggilan ke fungsi bernama changePage , yang akan segera kita lihat secara detail. Fungsi yang sama juga akan dipanggil dalam acara popstate , yang diaktifkan saat entri riwayat aktif browser berubah (seperti saat pengguna mengklik tombol kembali browser mereka):

 window.addEventListener('popstate', changePage);

Dengan semua ini, pada dasarnya kami sedang membangun sistem perutean yang sangat primitif, di mana kami memiliki mode aktif dan pasif.

Mode aktif kami digunakan saat pengguna mengklik tautan dan kami mengubah URL menggunakan pushState , sementara mode pasif digunakan saat URL berubah dan kami diberi tahu oleh acara popstate . Dalam kedua kasus tersebut, kita akan memanggil changePage , yang menangani pembacaan URL baru dan memuat halaman yang relevan.

Parsing dan Tambahkan Konten Baru

Biasanya, halaman yang dinavigasi akan memiliki elemen umum, seperti header dan footer . Misalkan kita menggunakan struktur DOM berikut di semua halaman kita (yang sebenarnya adalah struktur dari Smashing Magazine itu sendiri):

Menghidupkan!

Saat pengguna mengklik tautan, fungsi changePage mengambil HTML halaman itu, lalu mengekstrak wadah cc dan menambahkannya ke elemen main . Pada titik ini, kami memiliki dua wadah cc di halaman kami, yang pertama milik halaman sebelumnya dan yang kedua dari halaman berikutnya.

Fungsi berikutnya, animate , menangani crossfading dua kontainer dengan tumpang tindih, memudarkan yang lama, memudarkan yang baru dan menghapus kontainer lama. Dalam contoh ini, saya menggunakan Web Animations API untuk membuat animasi fade, tetapi tentu saja Anda dapat menggunakan teknik atau library apa pun yang Anda inginkan.

 function animate(oldContent, newContent) { oldContent.style.position = 'absolute'; var fadeOut = oldContent.animate({ opacity: [1, 0] }, 1000); var fadeIn = newContent.animate({ opacity: [0, 1] }, 1000); fadeIn.onfinish = function() { oldContent.parentNode.removeChild(oldContent); }; }

Kode terakhir tersedia di GitHub.

Dan itulah dasar-dasar transisi halaman web!

Peringatan Dan Batasan

Contoh kecil yang baru saja kita buat masih jauh dari sempurna. Sebenarnya, kami masih belum memperhitungkan beberapa hal:

  • Pastikan kami memengaruhi tautan yang benar.
    Sebelum mengubah perilaku tautan, kita harus menambahkan tanda centang untuk memastikan itu harus diubah. Misalnya, kita harus mengabaikan semua tautan dengan target="_blank" (yang membuka halaman di tab baru), semua tautan ke domain eksternal, dan beberapa kasus khusus lainnya, seperti Control/Command + click (yang juga membuka halaman di tab baru).
  • Perbarui elemen di luar wadah konten utama.
    Saat ini, saat halaman berubah, semua elemen di luar penampung cc tetap sama. Namun, beberapa elemen ini perlu diubah (yang sekarang hanya dapat dilakukan secara manual), termasuk title dokumen, elemen menu dengan kelas active , dan kemungkinan lainnya tergantung pada situs webnya.
  • Kelola siklus hidup JavaScript.
    Halaman kami sekarang berperilaku seperti SPA, di mana browser tidak mengubah halaman itu sendiri. Jadi, kita perlu menangani siklus hidup JavaScript secara manual — misalnya, mengikat dan melepaskan ikatan peristiwa tertentu, mengevaluasi kembali plugin, dan menyertakan polyfill dan kode pihak ketiga.

Dukungan Peramban

Satu-satunya persyaratan untuk mode navigasi yang kami terapkan ini adalah API pushState , yang tersedia di semua browser modern. Teknik ini bekerja sepenuhnya sebagai peningkatan progresif . Halaman masih disajikan dan dapat diakses dengan cara biasa, dan situs web akan terus bekerja secara normal saat JavaScript dinonaktifkan.

Jika Anda menggunakan kerangka kerja SPA, pertimbangkan untuk menggunakan navigasi PJAX, hanya untuk menjaga navigasi tetap cepat. Dengan melakukan itu, Anda mendapatkan dukungan warisan dan membuat situs web yang lebih ramah SEO.

Melangkah Lebih Jauh

Kami dapat terus mendorong batas teknik ini dengan mengoptimalkan aspek-aspek tertentu darinya. Beberapa trik berikutnya akan mempercepat navigasi, secara signifikan meningkatkan pengalaman pengguna.

Menggunakan Cache

Dengan sedikit mengubah fungsi loadPage , kita dapat menambahkan cache sederhana, yang memastikan bahwa halaman yang telah dikunjungi tidak dimuat ulang.

 var cache = {}; function loadPage(url) { if (cache[url]) { return new Promise(function(resolve) { resolve(cache[url]); }); } return fetch(url, { method: 'GET' }).then(function(response) { cache[url] = response.text(); return cache[url]; }); }

Seperti yang mungkin sudah Anda duga, kita dapat menggunakan cache yang lebih permanen dengan Cache API atau cache penyimpanan persisten sisi klien lainnya (seperti IndexedDB).

Menganimasikan Halaman Saat Ini

Efek crossfade kami mengharuskan halaman berikutnya dimuat dan siap sebelum transisi selesai. Dengan efek lain, kami mungkin ingin mulai menghidupkan halaman lama segera setelah pengguna mengeklik tautan, yang akan memberikan umpan balik langsung kepada pengguna, bantuan besar untuk kinerja yang dirasakan.

Dengan menggunakan janji, penanganan situasi seperti ini menjadi sangat mudah. Metode .all membuat janji baru yang diselesaikan segera setelah semua janji yang disertakan sebagai argumen diselesaikan.

 // As soon as animateOut() and loadPage() are resolved… Promise.all[animateOut(), loadPage(url)] .then(function(values) { …

Mengambil Halaman Berikutnya

Dengan hanya menggunakan navigasi PJAX, perubahan halaman biasanya hampir dua kali lebih cepat dari navigasi default, karena browser tidak harus mengurai dan mengevaluasi skrip atau gaya apa pun pada halaman baru.

Namun, kita dapat melangkah lebih jauh dengan mulai memuat halaman berikutnya saat pengguna mengarahkan kursor atau mulai menyentuh tautan.

Seperti yang Anda lihat, biasanya ada jeda 200 hingga 300 milidetik saat pengguna mengarahkan dan mengklik. Ini adalah waktu mati dan biasanya cukup untuk memuat halaman berikutnya.

Karena itu, ambil terlebih dahulu dengan bijak karena dapat dengan mudah menjadi hambatan. Misalnya, jika Anda memiliki daftar tautan yang panjang dan pengguna menggulirnya, teknik ini akan mengambil semua halaman terlebih dahulu karena tautannya lewat di bawah mouse.

Faktor lain yang dapat kami deteksi dan perhitungkan dalam memutuskan apakah akan melakukan prefetch adalah kecepatan koneksi pengguna. (Mungkin ini akan dimungkinkan di masa depan dengan API Informasi Jaringan.)

Keluaran Sebagian

Dalam fungsi loadPage kami, kami mengambil seluruh dokumen HTML, tetapi kami sebenarnya hanya membutuhkan wadah cc . Jika kita menggunakan bahasa sisi server, kita dapat mendeteksi apakah permintaan tersebut berasal dari panggilan AJAX khusus tertentu dan, jika demikian, hanya menampilkan wadah yang dibutuhkannya. Dengan menggunakan API Header, kami dapat mengirim tajuk HTTP khusus dalam permintaan pengambilan kami.

 function loadPage(url) { var myHeaders = new Headers(); myHeaders.append('x-pjax', 'yes'); return fetch(url, { method: 'GET', headers: myHeaders, }).then(function(response) { return response.text(); }); }

Kemudian, di sisi server (menggunakan PHP dalam kasus ini), kami dapat mendeteksi apakah header khusus kami ada sebelum hanya mengeluarkan wadah yang diperlukan:

 if (isset($_SERVER['HTTP_X_PJAX'])) { // Output just the container }

Ini akan mengurangi ukuran pesan HTTP dan juga mengurangi beban sisi server.

Membungkus

Setelah menerapkan teknik ini dalam beberapa proyek, saya menyadari bahwa perpustakaan yang dapat digunakan kembali akan sangat membantu. Ini akan menghemat waktu saya dalam menerapkannya pada setiap kesempatan, membebaskan saya untuk fokus pada efek transisi itu sendiri.

Maka lahirlah Barba.js, perpustakaan kecil (4 KB yang diperkecil dan gZip'd) yang mengabstraksi semua kerumitan ini dan menyediakan API yang bagus, bersih, dan sederhana untuk digunakan pengembang. Itu juga memperhitungkan tampilan dan dilengkapi dengan transisi, caching, prefetching, dan acara yang dapat digunakan kembali. Ini adalah open source dan tersedia di GitHub.

Kesimpulan

Kami telah melihat sekarang bagaimana membuat efek crossfade dan pro dan kontra menggunakan navigasi PJAX untuk secara efektif mengubah situs web kami menjadi SPA. Terlepas dari manfaat transisi itu sendiri, kita juga telah melihat bagaimana menerapkan mekanisme caching dan prefetching sederhana untuk mempercepat pemuatan halaman baru.

Seluruh artikel ini didasarkan pada pengalaman pribadi saya dan apa yang telah saya pelajari dari penerapan transisi halaman dalam proyek yang telah saya kerjakan. Jika Anda memiliki pertanyaan, jangan ragu untuk meninggalkan komentar atau hubungi saya di Twitter — info saya ada di bawah!

Bacaan Lebih Lanjut tentang SmashingMag:

  • Transisi Cerdas Dalam Desain Pengalaman Pengguna
  • Merancang Dalam Transisi Ke Dunia Multi-Perangkat
  • Memberikan Pengalaman Asli Dengan Teknologi Web