Ringkasan dasar tentang cara membuat scrollview horizontal responsif untuk TV, ponsel, desktop, dll.
Dalam postingan ini, saya ingin membagikan pemikiran tentang cara membuat pengalaman scroll horisontal untuk web yang minimal, responsif, mudah diakses, dan berfungsi di seluruh browser dan platform (seperti TV). Coba demo.
Jika Anda lebih suka video, berikut versi YouTube dari postingan ini:
Ringkasan
Kita akan membuat tata letak scroll horizontal yang dimaksudkan untuk menghosting thumbnail
media atau produk. Komponen dimulai sebagai daftar <ul>
sederhana, tetapi
diubah dengan CSS menjadi pengalaman scroll yang memuaskan dan lancar, yang menampilkan
gambar dan menyematkannya ke petak. JavaScript ditambahkan untuk memfasilitasi
interaksi indeks keliling, membantu pengguna keyboard melewati lebih dari 100 item.
Selain itu, kueri media eksperimental, prefers-reduced-data
, digunakan untuk mengubah
scroll media menjadi pengalaman scroll judul yang ringan.
Mulai dengan markup yang mudah diakses
Scroller media hanya terdiri dari beberapa komponen inti, yaitu daftar dengan item. Daftar, dalam bentuk paling sederhana, dapat menjangkau seluruh dunia dan dapat digunakan 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.
Kirim daftar dengan elemen <ul>
:
<ul class="horizontal-media-scroller">
<li></li>
<li></li>
<li></li>
...
<ul>
Buat 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
di <img>
. Teks alternatif untuk scroller
media adalah peluang UX untuk membantu memberikan konteks tambahan pada thumbnail, atau sebagai
teks pengganti jika gambar tidak dimuat, atau menyediakan UI lisan bagi pengguna
yang mengandalkan teknologi pendukung seperti pembaca layar. Pelajari lebih lanjut dengan Lima aturan
utama untuk teks
alternatif yang mematuhi kebijakan.
Atribut loading
menerima kata kunci lazy
sebagai cara untuk memberi sinyal bahwa sumber gambar ini
hanya boleh diambil jika gambar berada dalam area pandang. Hal ini dapat
sangat bagus untuk daftar besar, karena pengguna hanya akan mendownload gambar untuk item yang
di-scroll untuk dilihat.
Mendukung preferensi skema warna pengguna
Gunakan color-scheme
sebagai tag <meta>
untuk memberi sinyal ke browser bahwa halaman Anda
ingin 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 sedini mungkin, 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 enak dilihat.
Pelajari lebih lanjut dari Thomas Steiner di https://web.dev/color-scheme/.
Menambahkan konten
Dengan struktur konten ul > li > a > figure > picture > img
di atas,
tugas berikutnya adalah menambahkan gambar dan judul untuk di-scroll. Kami telah melengkapi demo dengan
gambar dan teks placeholder statis, tetapi jangan ragu untuk menggunakan data dari
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 dan aplikasi lainnya menggunakan area scrolling horisontal untuk memuat area pandang dengan kategori dan opsi.
Membuat tata letak penggeser
Sebaiknya hindari pemotongan konten dalam tata letak atau mengandalkan pemotongan teks dengan elipsis. Banyak set televisi memiliki scroll media seperti ini, tetapi sering kali menggunakan ellips konten. Tata letak ini tidak. Hal ini juga memungkinkan konten media mengganti ukuran kolom, sehingga 1 tata letak cukup fleksibel untuk menangani banyak kombinasi yang menarik.
Penampung memungkinkan penggantian ukuran kolom dengan memberikan ukuran default sebagai properti kustom. Tata letak petak ini memiliki pendapat tentang ukuran kolom, yang hanya mengelola spasi 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: 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 minor lainnya, selesaikan dasar-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 mengizinkan navigasi keyboard dan scrolling
melalui daftarnya, lalu setiap elemen <li>
turunan langsung akan menghapus ::marker
-nya
dengan mendapatkan jenis tampilan baru inline-block
.
Namun, gambar belum responsif, dan langsung keluar dari kotak tempatnya berada. Kendalikan dengan beberapa ukuran, kesesuaian, 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
Penyelarasan dengan konten halaman, ditambah area platform scroll dari tepi ke tepi, sangat penting untuk komponen yang harmonis dan minimal.
Untuk mencapai tata letak scroll dari tepi ke tepi yang selaras dengan garis tata letak
dan tipografi, 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 Gambar di atas menunjukkan betapa mudahnya menambahkan padding ke penampung scroll, tetapi ada masalah kompatibilitas yang belum terselesaikan (tetapi diperbaiki di Chromium 91+). Lihat di sini untuk mengetahui sedikit historinya, tetapi versi singkatnya adalah padding tidak selalu diperhitungkan dalam tampilan scroll.
Untuk mengelabui browser agar menempatkan padding di akhir penggeser, saya akan menargetkan angka terakhir di setiap daftar dan menambahkan elemen pseudo 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);
}
}
Penggunaan properti logis memungkinkan penggeser media berfungsi dalam mode penulisan dan arah dokumen apa pun.
Pengepasan posisi scroll
Penampung scroll dengan overflow dapat menjadi area pandang snap dengan satu baris CSS, lalu turunan harus menentukan cara mereka ingin menyelaraskan dengan area pandang 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 scroll media yang sangat mirip dengan ini, sebagai tata letak layar utama utamanya. Fokus adalah momen UX yang besar, bukan hanya tambahan kecil. Bayangkan Anda menggunakan scroll 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 menetapkan gaya garis batas fokus 7px
dari kotak, sehingga memberikan ruang
yang bagus. Jika pengguna tidak memiliki preferensi gerakan terkait pengurangan gerakan, offset
akan ditransisikan, sehingga memberikan gerakan halus ke peristiwa fokus.
Indeks keliling
Pengguna gamepad dan keyboard memerlukan perhatian khusus dalam daftar panjang konten dan opsi scroll ini. Pola umum untuk mengatasi hal ini disebut indeks keliling. Hal ini terjadi saat penampung item difokuskan keyboard, tetapi hanya 1 turunan yang diizinkan untuk mempertahankan fokus sekaligus. Pengalaman item tunggal yang dapat difokuskan ini dirancang untuk memungkinkan pengabaian daftar item yang berpotensi panjang, bukan menekan tab lebih dari 50 kali untuk mencapai bagian akhir.
Ada 300 item di penggeser pertama demo tersebut. Kita dapat melakukan lebih baik daripada membuat mereka menjelajahi semuanya untuk mencapai bagian berikutnya.
Untuk membuat pengalaman ini, JavaScript perlu mengamati peristiwa keyboard dan peristiwa fokus. Saya membuat library open source kecil di npm untuk membantu membuat pengalaman pengguna ini mudah dicapai. Berikut cara menggunakannya untuk 3 penggeser:
import {rovingIndex} from 'roving-ux';
rovingIndex({
element: someElement
});
Demo ini membuat kueri dokumen untuk penggeser dan untuk setiap penggeser, kueri ini memanggil
fungsi rovingIndex()
. Teruskan elemen rovingIndex()
untuk mendapatkan pengalaman
berpindah, seperti penampung daftar, dan pemilih kueri target, jika
target fokus bukan merupakan turunan langsung.
document.querySelectorAll('.horizontal-media-scroller')
.forEach(scroller =>
rovingIndex({
element: scroller,
target: 'a',
}))
Untuk mempelajari efek ini lebih lanjut, lihat library open source roving-ux.
Rasio aspek
Saat menulis postingan ini, 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 spasi, ukurannya dapat
berubah di dalam kueri media yang fiturnya memeriksa dukungan rasio aspek.
Progressive enhancement ke beberapa scroll 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 susunan bertingkat draf, setiap gambar
akan mengubah rasio aspeknya, bergantung pada apakah gambar tersebut berada di baris pertama, kedua, atau ketiga. Sintaksis bertingkat juga memungkinkan penetapan beberapa penyesuaian area pandang
kecil, tepat di sana dengan logika penskalaan 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 diringkas
Meskipun teknik berikutnya ini hanya tersedia
di balik flag di
Canary,
saya ingin membagikan cara menghemat waktu pemuatan halaman dan
penggunaan data yang cukup besar dengan beberapa baris CSS. Kueri media prefers-reduced-data
dari
level 5 memungkinkan pertanyaan 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 yang berat. Berikut adalah situs sebelum menambahkan CSS prefers-reduced-data
:
(7 permintaan, 100 kb resource dalam 131 md)
Berikut adalah performa situs setelah menambahkan CSS prefers-reduced-data
:
(71 permintaan, resource 1,2 mb dalam 1,07 detik)
64 permintaan lebih sedikit, yang akan menjadi ~60 gambar dalam area pandang (pengujian dilakukan di layar lebar) dari tab browser ini, peningkatan pemuatan halaman sebesar ~80%, dan 10% data melalui jaringan. CSS yang cukup canggih.
Kesimpulan
Setelah Anda tahu cara saya melakukannya, bagaimana Anda melakukannya? 🙂
Mari kita diversifikasi pendekatan dan pelajari semua cara untuk mem-build di web. Buat Codepen atau host demo Anda sendiri, tweet ke saya, dan saya akan menambahkannya ke bagian Remix komunitas di bawah.
Sumber
Remix komunitas
Belum ada apa-apa di sini.