Ringkasan dasar tentang cara membuat scrollview horizontal responsif untuk TV, ponsel, desktop, dll.
Dalam postingan ini, saya ingin berbagi pemikiran tentang cara membuat pengalaman scroll horizontal untuk web yang minimal, responsif, mudah diakses, dan berfungsi di berbagai browser dan platform (seperti TV). Coba demo.
Jika Anda lebih suka menonton video, berikut versi YouTube dari postingan ini:
Ringkasan
Kita akan membuat tata letak scroll horizontal yang ditujukan untuk menghosting thumbnail media atau produk. Komponen dimulai sebagai daftar <ul>
sederhana, tetapi
diubah dengan CSS menjadi pengalaman scroll yang memuaskan dan lancar, menampilkan
gambar dan menyelaraskannya ke petak. JavaScript ditambahkan untuk memfasilitasi interaksi indeks roaming, membantu pengguna keyboard melewati penelusuran lebih dari 100 item.
Selain itu, kueri media eksperimental, prefers-reduced-data
, digunakan untuk mengubah
penggeser media menjadi pengalaman penggeser judul ringan.
Mulai dengan markup yang dapat diakses
Penggeser media dibuat dari beberapa komponen inti, yaitu daftar dengan item. Daftar, dalam bentuknya yang paling sederhana, dapat melakukan perjalanan ke seluruh dunia dan dapat dipahami dengan jelas oleh semua orang. Pengguna yang membuka halaman ini dapat menjelajahi daftar dan mengklik link untuk melihat item. Ini adalah basis yang dapat diakses.
Menampilkan daftar dengan elemen <ul>
:
<ul class="horizontal-media-scroller">
<li></li>
<li></li>
<li></li>
...
<ul>
Jadikan item daftar interaktif dengan elemen <a>
:
<li>
<a href="#">
...
</a>
</li>
Gunakan elemen <figure>
untuk merepresentasikan gambar dan teksnya secara semantik:
<figure>
<picture>
<img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
</picture>
<figcaption>Legends</figcaption>
</figure>
Perhatikan atribut alt
dan loading
pada <img>
. Teks alternatif untuk penggeser media adalah peluang UX untuk membantu memberikan konteks tambahan pada thumbnail, atau sebagai teks pengganti jika gambar tidak dimuat, atau memberikan UI lisan bagi pengguna yang mengandalkan teknologi pendukung seperti pembaca layar. Pelajari lebih lanjut dengan Lima aturan emas untuk teks alternatif yang sesuai.
Atribut loading
menerima kata kunci lazy
sebagai cara untuk memberi sinyal bahwa sumber gambar ini hanya boleh diambil saat gambar berada dalam area tampilan. Hal ini dapat
sangat berguna untuk daftar besar, karena pengguna hanya akan mendownload gambar untuk item yang
di-scroll ke dalam tampilan.
Mendukung preferensi skema warna pengguna
Gunakan color-scheme
sebagai tag <meta>
untuk memberi sinyal kepada browser bahwa halaman Anda menginginkan gaya agen pengguna terang dan gelap yang disediakan. Ini adalah mode gelap atau mode terang gratis, bergantung pada cara Anda melihatnya:
<meta name="color-scheme" content="dark light">
Tag meta memberikan sinyal paling awal yang memungkinkan, sehingga browser dapat memilih warna kanvas default gelap jika pengguna memiliki preferensi tema gelap. Artinya, navigasi antarhalaman situs tidak akan menampilkan latar belakang kanvas putih di antara pemuatan. Tema gelap yang lancar di antara pemuatan, jauh lebih nyaman di mata.
Pelajari lebih lanjut dari Thomas Steiner di https://web.dev/color-scheme/.
Tambahkan konten
Mengingat struktur konten ul > li > a > figure > picture > img
di atas, tugas berikutnya adalah menambahkan gambar dan judul untuk menelusuri. Saya telah melengkapi demo dengan gambar dan teks placeholder statis, tetapi Anda dapat menggunakan sumber data favorit Anda.
Menambahkan gaya dengan CSS
Sekarang saatnya CSS mengambil daftar konten generik ini dan mengubahnya menjadi pengalaman. Netflix, App Store, dan banyak situs serta aplikasi lainnya menggunakan area scroll horizontal untuk mengisi area tampilan dengan kategori dan opsi.
Membuat tata letak scroller
Anda harus menghindari pemotongan konten dalam tata letak atau mengandalkan pemotongan teks dengan elipsis. Banyak televisi memiliki penjelajah media seperti ini, tetapi sering kali menggunakan elipsis untuk konten. Tata letak ini tidak! Tata letak ini juga memungkinkan konten media menggantikan ukuran kolom, sehingga 1 tata letak cukup fleksibel untuk menangani banyak kombinasi menarik.
Penampung memungkinkan penggantian ukuran kolom dengan memberikan ukuran default sebagai properti kustom. Tata letak petak ini memiliki pendapat tentang ukuran kolom, hanya mengelola jarak dan arah:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
margin: 0;
}
Properti kustom kemudian digunakan oleh elemen <picture>
untuk membuat rasio aspek dasar kita: kotak:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
Dengan hanya beberapa gaya kecil lagi, selesaikan kerangka dasar penggeser media:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
& > li {
display: inline-block; /* removes the list-item bullet */
}
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
Menetapkan overflow
akan menyiapkan <ul>
untuk memungkinkan scrolling dan navigasi keyboard
melalui daftarnya, lalu setiap elemen turunan langsung <li>
akan dihapus ::marker
-nya
dengan mendapatkan jenis tampilan baru inline-block
.
Namun, gambar belum responsif, dan keluar dari kotak tempat gambar berada. Atur dengan beberapa ukuran, kecocokan, dan gaya batas, serta gradien latar belakang saat dimuat lambat:
img {
/* smash into whatever box it's in */
inline-size: 100%;
block-size: 100%;
/* don't squish but do cover the space */
object-fit: cover;
/* soften the edges */
border-radius: 1ex;
overflow: hidden;
/* if empty, show a gradient placeholder */
background-image:
linear-gradient(
to bottom,
hsl(0 0% 40%),
hsl(0 0% 20%)
);
}
Padding scroll
Penyesuaian dengan konten halaman, ditambah luas area scroll dari ujung ke ujung, sangat penting untuk komponen yang harmonis dan minimal.
Untuk mendapatkan tata letak scroll layar penuh yang selaras dengan tipografi
dan garis tata letak kami, gunakan padding
yang cocok dengan scroll-padding
:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
padding-inline: var(--gap);
scroll-padding-inline: var(--gap);
padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}
Perbaikan bug padding scroll horizontal Di atas menunjukkan betapa mudahnya memberi padding pada penampung scroll, tetapi ada masalah kompatibilitas yang belum terselesaikan (telah diperbaiki di Chromium 91+). Lihat di sini untuk mengetahui sedikit histori, tetapi versi singkatnya adalah padding tidak selalu diperhitungkan dalam tampilan scroll.
Untuk mengakali browser agar menempatkan padding di akhir scroller, saya akan menargetkan angka terakhir di setiap daftar dan menambahkan elemen semu yang merupakan jumlah padding yang diinginkan.
.horizontal-media-scroller > li:last-of-type figure {
position: relative;
&::after {
content: "";
position: absolute;
inline-size: var(--gap);
block-size: 100%;
inset-block-start: 0;
inset-inline-end: calc(var(--gap) * -1);
}
}
Dengan menggunakan properti logis, penggeser media dapat berfungsi dalam mode penulisan dan arah dokumen apa pun.
Pengepasan posisi scroll
Penampung scroll dengan konten yang meluap dapat menjadi area tampilan yang menyentak dengan satu baris CSS, lalu turunan akan menentukan cara mereka ingin disejajarkan dengan area tampilan tersebut.
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
padding-inline: var(--gap);
scroll-padding-inline: var(--gap);
padding-block-end: calc(var(--gap) / 2);
scroll-snap-type: inline mandatory;
& figure {
scroll-snap-align: start;
}
}
Fokus
Inspirasi untuk komponen ini berasal dari popularitasnya yang sangat besar di TV, di App Store, dan lainnya. Banyak platform video game menggunakan penggeser media yang sangat mirip dengan ini, sebagai tata letak layar utama mereka. Fokus adalah momen UX yang sangat penting di sini, bukan hanya tambahan kecil. Bayangkan menggunakan penggeser media ini dari sofa dengan remote, berikan beberapa peningkatan kecil pada interaksi tersebut:
.horizontal-media-scroller a {
outline-offset: 12px;
&:focus {
outline-offset: 7px;
}
@media (prefers-reduced-motion: no-preference) {
& {
transition: outline-offset .25s ease;
}
}
}
Tindakan ini akan menyetel gaya garis batas fokus 7px
menjauhi kotak, sehingga memberikan ruang yang cukup. Jika pengguna tidak memiliki preferensi gerakan terkait mengurangi gerakan, offset akan ditransisikan, sehingga memberikan gerakan halus pada peristiwa fokus.
Indeks roaming
Pengguna gamepad dan keyboard memerlukan perhatian khusus dalam daftar panjang konten dan opsi yang dapat di-scroll ini. Pola umum untuk menyelesaikan masalah ini disebut indeks bergerak. Saat penampung item difokuskan keyboard, tetapi hanya 1 turunan yang diizinkan untuk mempertahankan fokus pada satu waktu. Pengalaman satu item yang dapat difokuskan dalam satu waktu ini dirancang untuk memungkinkan melewati daftar item yang berpotensi panjang, alih-alih menekan tab lebih dari 50 kali untuk mencapai akhir.
Ada 300 item di scroller pertama demo tersebut. Kita bisa melakukan yang lebih baik daripada membuat mereka menjelajahi semuanya untuk mencapai bagian berikutnya.
Untuk menciptakan pengalaman ini, JavaScript perlu mengamati peristiwa keyboard dan peristiwa fokus. Saya membuat library open source kecil di npm untuk membantu mempermudah pencapaian pengalaman pengguna ini. Berikut cara menggunakannya untuk 3 scroller:
import {rovingIndex} from 'roving-ux';
rovingIndex({
element: someElement
});
Demo ini mengkueri dokumen untuk scroller dan untuk setiap scroller memanggil fungsi
rovingIndex()
. Teruskan rovingIndex()
elemen untuk mendapatkan pengalaman
berpindah-pindah, seperti penampung daftar, dan pemilih kueri target, jika
target fokus bukan turunan langsung.
document.querySelectorAll('.horizontal-media-scroller')
.forEach(scroller =>
rovingIndex({
element: scroller,
target: 'a',
}))
Untuk mempelajari lebih lanjut efek ini, lihat library open source roving-ux.
Rasio aspek
Saat postingan ini ditulis, dukungan untuk
aspect-ratio
berada di balik
flag di Firefox, tetapi tersedia di browser Chromium atau set-top box. Karena tata letak petak penggeser media hanya menentukan arah dan jarak, ukuran dapat berubah di dalam kueri media yang memeriksa dukungan rasio aspek.
Peningkatan progresif ke beberapa penggeser media yang lebih dinamis.
@supports (aspect-ratio: 1) {
.horizontal-media-scroller figure > picture {
inline-size: auto; /* for a block-size driven ratio */
aspect-ratio: 1; /* boxes by default */
@nest section:nth-child(2) & {
aspect-ratio: 16/9;
}
@nest section:nth-child(3) & {
/* double the size of the others */
block-size: calc(var(--size) * 2);
aspect-ratio: 4/3;
/* adjust size to fit more items into the viewport */
@media (width <= 480px) {
block-size: calc(var(--size) * 1.5);
}
}
}
}
Jika browser mendukung sintaksis aspect-ratio
, gambar penggeser media akan diupgrade ke ukuran aspect-ratio
. Dengan menggunakan sintaksis penyusunan draf, setiap gambar
mengubah rasio aspeknya, bergantung pada apakah gambar tersebut berada di baris pertama, kedua, atau ketiga. Sintaksis bertingkat juga memungkinkan penetapan beberapa penyesuaian
viewport kecil, tepat di sana dengan logika penetapan ukuran lainnya.
Dengan CSS tersebut, karena fitur ini tersedia di lebih banyak mesin browser, tata letak yang mudah dikelola, tetapi lebih menarik secara visual akan dirender.
Lebih memilih data yang dikurangi
Meskipun teknik berikutnya hanya tersedia
di balik tanda di
Canary,
saya ingin membagikan cara saya dapat menghemat waktu pemuatan halaman dan
penggunaan data dalam jumlah yang cukup besar dengan beberapa baris CSS. Kueri media prefers-reduced-data
dari
level 5 memungkinkan untuk menanyakan apakah perangkat berada dalam
status data yang dikurangi, seperti mode penghemat data. Jika ya, saya dapat mengubah dokumen, dan dalam hal ini, menyembunyikan gambar.
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
Konten masih dapat dijelajahi, tetapi tanpa biaya untuk mendownload gambar berukuran besar. Berikut situs sebelum menambahkan CSS prefers-reduced-data
:
(7 permintaan, 100 kb resource dalam 131 md)
Berikut performa situs setelah menambahkan CSS prefers-reduced-data
:
(71 permintaan, 1,2 MB resource dalam 1,07 dtk)
64 permintaan lebih sedikit, yaitu ~60 gambar dalam area tampilan (pengujian dilakukan di layar lebar) tab browser ini, peningkatan pemuatan halaman sebesar ~80%, dan 10% data melalui jaringan. CSS yang cukup canggih.
Kesimpulan
Sekarang setelah Anda tahu cara saya melakukannya, bagaimana Anda?! 🙂
Mari kita diversifikasi pendekatan kita dan pelajari semua cara untuk membangun di web. Buat Codepen atau hosting demo Anda sendiri, kirimkan tweet kepada saya, dan saya akan menambahkannya ke bagian Remix komunitas di bawah.
Sumber
Remix komunitas
Belum ada apa-apa di sini.