Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Code
  2. JavaScript
Code

Membuat Carousel Yang Sempurna, Bagian 1

by
Difficulty:AdvancedLength:LongLanguages:
This post is part of a series called Create the Perfect Carousel.
Create the Perfect Carousel, Part 2

Indonesian (Bahasa Indonesia) translation by Andy Nur (you can also view the original English article)

Carousels adalah bahan pokok dari situs streaming dan e-commerce. Baik Amazon dan Netflix menggunakannya sebagai tool navigasi yang menonjol. Dalam tutorial ini, kita akan mengevaluasi desain interaksi keduanya, dan menggunakan temuan kita untuk menerapkan carousel yang sempurna.

Dalam rangkaian tutorial ini, kita juga akan mempelajari beberapa fungsi Popmotion, motion engine JavaScript. Ini menawarkan tool animasi seperti tweens (berguna untuk pagination), pelacakan pointer (untuk pengguliran), dan fisika pegas (untuk sentuhan akhir yang menyenangkan.)

Bagian 1 akan mengevaluasi bagaimana Amazon dan Netflix telah menerapkan pengguliran. Kita kemudian akan menerapkan carousel yang dapat digulirkan melalui sentuhan.

Pada akhir seri ini, kita akan menerapkan gulungan roda dan touchpad, pagination, progress bar, navigasi keyboard, dan beberapa sentuhan kecil yang menggunakan teknik fisika pegas. Kita juga akan memaparkan beberapa komposisi fungsional dasar.

Sempurna?

Apa yang dibutuhkan agar sebuah carousel menjadi "sempurna"? Ini harus dapat diakses oleh:

  • Mouse: Ini harus menawarkan tombol sebelumnya dan berikutnya yang mudah diklik dan tidak mengaburkan konten.
  • Touch: Harus melacak jari, lalu digulir dengan momentum yang sama seperti saat jari diangkat dari layar.
  • Scroll wheel: Sering diabaikan, Apple Magic Mouse dan banyak trackpad laptop menawarkan pengguliran horizontal yang halus. Kita harus memanfaatkan kemampuan itu!
  • Keyboard: Banyak pengguna memilih untuk tidak melakukannya, atau tidak dapat menggunakan mouse untuk navigasi. Penting agar carousel kita bisa diakses sehingga pengguna bisa menggunakan produk kita juga.

Akhirnya, kita akan melakukan hal-hal yang melangkah lebih jauh dan membuat ini menjadi bagian UX yang percaya diri dan menyenangkan dengan membuat carousel merespon dengan jelas dan secara mendalam dengan fisika pegas saat slider sudah mencapai akhir.

Pengaturan

Pertama, mari kita bahas HTML dan CSS yang diperlukan untuk membuat carousel yang belum sempurna dengan meng-fork CodePen ini.

Pen dibuat dengan Sass untuk preprocessing CSS dan Babel untuk mentransmisikan ES6 JavaScript. Saya juga menyertakan Popmotion, yang bisa diakses dengan window.popmotion.

Kamu dapat menyalin kode ke proyek lokal jika kamu mau, namun kamu harus memastikan lingkungan kerjamu mendukung Sass dan ES6. Kamu juga perlu menginstal Popmotion dengan npm install popmotion.

Membuat Carousel Baru

Pada halaman tertentu, kita mungkin memiliki banyak carousel. Jadi kita membutuhkan metode untuk merangkum state dan fungsinya masing-masing.

Saya akan menggunakan fungsi factory daripada sebuah class. Fungsi factory menghindari kebutuhan untuk menggunakan kata this yang sering membingungkan dan akan mempermudah kode untuk keperluan tutorial ini.

Di editor JavaScript-mu, tambahkan fungsi sederhana ini:

Kita akan menambahkan kode spesifik-carousel kita di dalam fungsi carousel ini.

Bagiamana dan Mengapa Pengguliran

Tugas pertama kita adalah membuat guliran carousel. Ada dua cara yang bisa kita lakukan:

Pengguliran Asli Browser

Solusi yang jelas adalah mengatur overflow-x: scroll pada slider. Ini akan memungkinkan penggulir asli pada semua browser, termasuk sentuhan dan perangkat roda mouse horizontal.

Namun ada kelemahan untuk pendekatan ini:

  • Konten di luar wadah tidak akan terlihat, yang bisa membatasi desain kita.
  • Ini juga membatasi cara kita dapat menggunakan animasi untuk menunjukkan bahwa kita telah mencapai akhir.
  • Browser desktop akan memiliki bilah gulir horizontal yang jelek (meski mudah diakses!).

Kalau tidak:

Animate translateX

Kita juga bisa menghidupkan properti translateX carousel itu. Ini akan sangat serbaguna karena kita bisa menerapkan desain yang tepat yang kita sukai. translateX juga sangat bekerja, karena tidak seperti properti CSS left yang itu dapat ditangani oleh perangkat GPU.

Pada sisi negatifnya, kita harus mengimplementasi ulang fungsi pengguliran menggunakan JavaScript. Itu lebih banyak pekerjaan, lebih banyak kode.

Bagaimana Pendekatan Pengguliran Amazon dan Netflix?

Baik carousel Amazon dan Netflix membuat penawaran yang berbeda dalam mendekati masalah ini.

Amazon menganimasi properti left carousel saat berada dalam mode "desktop". Menganimasikan left adalah pilihan yang sangat buruk, karena mengubahnya memicu perhitungan ulang tata letak. Ini adalah CPU-intensif, dan mesin yang lebih tua akan berjuang untuk mengenai 60fps.

Siapa pun yang membuat keputusan untuk menganimasi left daripada translateX pasti benar-benar idiot (spoiler: itu adalah saya, pada tahun 2012. Kami tidak begitu tercerahkan pada masa itu.)

Saat mendeteksi perangkat sentuh, carousel menggunakan pengguliran asli browser. Masalahnya hanya dengan mengaktifkan mode "mobile" ini adalah pengguna desktop dengan roda gulir horizontal yang tidak ada. Ini juga berarti konten di luar carousel harus diputar secara visual:

Screenshot of Amazon illustrating lack of design bleed

Netflix menganimasi dengan benar properti translateX carousel itu, dan hal itu terjadi pada semua perangkat. Hal ini memungkinkan mereka memiliki desain yang melukai di luar carousel:

Screenshot of Netflix carousel illustrating design bleed

Hal ini, pada gilirannya, memungkinkan mereka untuk membuat desain yang mewah di mana item diperbesar di luar sudut x dan y dari carousel dan barang-barang disekitarnya bergerak keluar dari jalan mereka:

Screenshot of Netflix carousel illustrating enlarged item

Sayangnya, implementasi ulang perangkat bergulir Netflix untuk perangkat sentuh tidak memuaskan: ia menggunakan sistem pagination berbasis gesture yang terasa lamban dan tidak praktis. Juga tidak ada pertimbangan untuk roda gulir horisontal.

Kita bisa berbuat lebih baik. Mari kita kode!

Pengguliran Seperti Profesional

Langkah pertama kita adalah meraih node .slider. Sementara kita melakukannya, mari ambil item yang dikandungnya sehingga kita bisa mengetahui dimensi slider.

Mengukur Carousel

Kita bisa mengetahui area yang terlihat dari slider dengan mengukur lebarnya:

Kita juga menginginkan total lebar semua item yang ada di dalamnya. Agar fungsi carousel kita tetap relatif rapi, mari kita letakkan perhitungan ini di fungsi terpisah di bagian atas file kita.

Dengan menggunakan getBoundingClientRect untuk mengukur offset left item pertama kita dan offset right item terakhir kita, kita dapat menggunakan perbedaan di antara keduanya untuk menemukan lebar total semua item.

Setelah pengukuran sliderVisibleWidth kita, tulis:

Kita sekarang bisa mengetahui jarak maksimum carousel kita yang boleh digulir. Ini adalah total lebar semua item kita, minus satu lebar penuh dari slider yang kita lihat. Ini menyediakan nomor yang memungkinkan item paling kanan untuk disesuaikan dengan benar pada slider kita:

Dengan pengukuran ini, kita siap untuk mulai menggulir carousel kita.

Pengaturan translateX

Popmotion hadir dengan perender CSS untuk pengaturan CSS dan layanan yang sederhana. Ini juga dilengkapi dengan fungsi nilai yang dapat digunakan untuk melacak angka dan, yang penting (seperti yang akan kita lihat), untuk query kecepatannya.

Di bagian atas file JavaScript-mu, impor mereka seperti:

Kemudian, pada baris setelah kita menetapkan minXOffset, buatlah perender CSS untuk slider kita:

Dan buat value untuk melacak slider kita x offset dan perbarui properti translateX slider saat ini berubah:

Sekarang, pindahkan slider secara horizontal semudah menulis:

Cobalah!

Sentuh Gulir

Kami ingin carouse kita mulai bergulir saat pengguna menyeret slider secara horizontal dan berhenti bergulir saat pengguna berhenti menyentuh layar. Event handler kita akan terlihat seperti ini:

Dalam fungsi startTouchScroll kita, kita ingin:

  • Menghentikan aksi lain yang menggerakkan sliderX.
  • Temukan sumber titik sentuhan.
  • Perhatikan event touchmove berikutnya untuk melihat apakah pengguna menyeret secara vertikal atau horizontal.

Setelah document.addEventListener, tambahkan:

Ini akan menghentikan aksi lain (seperti gulir momentum bertenaga fisika yang akan kita implementasikan di stopTouchScroll) agar tidak memindahkan slider. Ini akan memungkinkan pengguna untuk segera "menangkap" slider jika menggulir melewati item atau judul yang ingin mereka klik.

Selanjutnya, kita perlu menyimpan titik sentuhan asal. Itu akan memungkinkan kita untuk melihat di mana pengguna menggerakkan jari mereka berikutnya. Jika itu gerakan vertikal, kita akan mengizinkan penggulir halaman seperti biasa. Jika itu adalah gerakan horizontal, kita akan menggulir slider sebagai gantinya.

Kita ingin membagi touchOrigin ini di antara event handler. Jadi setelah let action; tambahkan:

Kembali ke handler startTouchScroll kita, tambahkan:

Kita sekarang dapat menambahkan event listener touchmove ke document untuk menentukan arah seret berdasarkan touchOrigin ini:

Fungsi determineDragDirection kita akan mengukur lokasi sentuhan berikutnya, memeriksanya apa benar-benar bergerak dan, jika demikian, ukur sudutnya untuk menentukan apakah vertikal atau horizontal:

Popmotion mencakup beberapa kalkulator yang membantu untuk mengukur hal-hal seperti jarak antara dua koordinat x/y. Kita bisa mengimpornya seperti ini:

Kemudian mengukur jarak antara kedua titik tersebut adalah masalah menggunakan kalkulator distance:

Nah jika sentuhan sudah dipindah, kita bisa tidak mengeset event listener ini.

Ukur sudut antara dua titik dengan kalkulator angle:

Kita bisa menggunakan ini untuk menentukan apakah sudut ini sudut horizontal atau vertikal, dengan meneruskannya ke fungsi berikut. Tambahkan fungsi ini ke bagian paling atas dari file kita:

Fungsi ini mengembalikan nilai true jika sudut yang diberikan berada di dalam -90 +/- 45 derajat (lurus ke atas) atau 90 +/- 45 derajat (lurus ke bawah.) Jadi, kita dapat menambahkan ketentuan return yang lain jika fungsi ini mengembalikan nilai true.

Pelacakan Pointer

Sekarang kita tahu pengguna sedang mencoba menggulir carousel, kita bisa mulai melacak jarinya. Popmotion menawarkan aksi pointer yang akan menampilkan koordinat x/y dari mouse atau pointer sentuh.

Pertama, impor pointer:

Untuk melacak inputan sentuh, berikan event yang berasal ke pointer:

Kita ingin mengukur posisi awal x dari pointer kita dan menerapkan gerakan apapun ke slider. Untuk itu, kita dapat menggunakan transformer yang disebut applyOffset.

Transformer adalah fungsi murni yang mengambil nilai, dan mengembalikannya—ya—berubah. Misalnya: const double = (v) => v * 2.

applyOffset adalah fungsi curry. Maksudnya bahwa ketika kita menyebutnya, itu menciptakan fungsi baru yang kemudian bisa diberi nilai. Kita pertama kali menyebutnya dengan nomor yang ingin kita ukur offset darinya, dalam hal ini yaitu nilai action.x saat ini, dan sebuah angka untuk menerapkan offset itu. Dalam kasus ini, itu adalah sliderX kita.

Jadi fungsi applyOffset kita akan terlihat seperti ini:

Kita sekarang dapat menggunakan fungsi ini pada callback output pointer untuk menerapkan gerakan pointer ke slider.

Berhenti, Dengan Style

Carousel sekarang dapat diseret dengan sentuhan! Kamu dapat mengujinya dengan menggunakan emulasi perangkat di Chrome's Developer Tools.

Rasanya sedikit mengesalkan, kan? Kamu mungkin pernah mengalami pengguliran yang terasa seperti ini sebelumnya: Kamu mengangkat jarimu, dan pengguliran berhenti mati. Atau pengguliran berhenti mati dan kemudian animasi kecil mengambil alih untuk menyamarkan kelanjutan dari pengguliran tersebut.

Kami tidak akan melakukan itu. Kita bisa menggunakan aksi fisika di Popmotion untuk mengambil kecepatan sebenarnya dari sliderX dan menerapkan pergeseran ke dalamnya selama durasi waktu.

Pertama, tambahkan ini ke daftar impor kita yang terus berkembang:

Kemudian, di akhir fungsi stopTouchScroll kita, tambahkan:

Di sini, from dan velocity diatur dengan nilai sekarang dan kecepatan sliderX. Hal ini memastikan simulasi fisika kita memiliki kondisi awal yang sama dengan gerakan menyeret pada pengguna.

friction ditetapkan sebagai 0.2. Pergeseran diatur sebagai nilai dari 0 sampai 1, dengan 0 tidak ada pergeseran sama sekali dan 1 merupakan pergeseran absolut. Cobalah bermain-main dengan nilai ini untuk melihat perubahan yang terjadi pada "perasaan" carousel saat pengguna berhenti menyeret.

Jumlah yang lebih kecil akan membuatnya terasa lebih ringan, dan jumlah yang lebih besar akan membuat gerakan lebih berat. Untuk gerakan bergulir, saya rasa 0.2 menyentuh keseimbangan yang bagus antara tidak menentu dan lamban.

Batas

Tapi ada masalah! Jika kamu telah bermain-main dengan carousel sentuh barumu, sudah jelas. Kita tidak membatasi gerakan, sehingga memungkinkan untuk benar-benar membuang carousel-mu pergi!

Ada transformator lain untuk pekerjaan ini, clamp. Ini juga merupakan fungsi curry, artinya jika kita menyebutnya dengan nilai min dan max, katakanlah 0 dan 1, itu akan mengembalikan fungsi baru. Dalam contoh ini, fungsi baru akan membatasi jumlah yang diberikan padanya antara 0 dan 1:

Pertama, impor clamp:

Kita ingin menggunakan fungsi penjempit ini di seluruh carousel kita, jadi tambahkan baris ini setelah kita mendefinisikan minXOffset:

Kita akan mengubah dua output yang telah kita tetapkan pada aksi kita dengan menggunakan beberapa komposisi fungsional ringan dengan transformer pipe.

Pipe

Saat kita memanggil fungsi, kita menuliskannya seperti ini:

Jika kita ingin memberikan output dari fungsi itu ke fungsi lain, kita mungkin menuliskannya seperti ini:

Ini menjadi sedikit sulit untuk dibaca, dan itu semakin memburuk saat kita menambahkan lebih banyak fungsi.

Dengan pipe, kita bisa membuat fungsi baru dari foo dan bar yang bisa kita gunakan kembali:

Ini juga ditulis dalam awal normal -> urutan akhir, yang membuatnya lebih mudah diikuti. Kita bisa menggunakan ini untuk menyusun applyOffset dan clamp menjadi satu fungsi. Impor pipe:

Ganti callback output dari pointer kita dengan:

Dan ganti callback output dari physics dengan:

Komposisi fungsional semacam ini bisa cukup rapi membuatnya deskriptif, proses langkah-demi-langkah lebih kecil, fungsi yang dapat digunakan kembali.

Sekarang, ketika kamu menyeret dan melempar carousel, tidak akan bergerak keluar dari batas-batasnya.

Tiba-tiba berhenti tidak terlalu memuaskan. Tapi itu masalah untuk nanti!

Kesimpulan

Itu semua untuk bagian 1. Sejauh ini, kita telah melihat-lihat carousel yang ada untuk melihat kekuatan dan kelemahan dari berbagai pendekatan untuk pengguliran. Kita telah menggunakan pelacakan inputan dan fisika Popmotion untuk menampilkan animasi translateX carousel kita dengan sentuhan bergulir. Kita juga telah diperkenalkan pada komposisi fungsional dan fungsi curry.

Kamu bisa mengambil versi komentar dari "cerita sejauh ini" pada CodePen ini.

Dalam angsuran mendatang, kita akan melihat:

  • pengguliran dengan roda mouse
  • mengukur ulang carousel saat window berubah ukuran
  • paginasi, dengan aksesibilitas keyboard dan mouse
  • sentuhan menyenangkan, dengan bantuan fisika musim semi

Berharap untuk melihatmu di sana!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.