Membuat komponen scroller media

Ringkasan dasar tentang cara membuat tampilan scroll horizontal yang 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 seluruh browser dan platform (seperti TV!). Coba demonya.

Demo

Jika Anda lebih suka video, berikut versi YouTube 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 memasukkannya ke petak. JavaScript ditambahkan untuk memfasilitasi interaksi indeks penjelajah, yang membantu pengguna keyboard melewati 100+ item. Selain itu, kueri media eksperimental, prefers-reduced-data, digunakan untuk mengubah scroller media menjadi pengalaman scroller judul yang ringan.

Mulai dengan markup yang dapat diakses

Scroller media hanya terdiri dari beberapa komponen inti, yaitu daftar berisi item. Sebuah daftar, dalam bentuknya yang paling sederhana, dapat berpindah ke seluruh dunia dan dengan jelas dipakai oleh semua orang. Pengguna yang membuka halaman ini dapat menjelajahi daftar dan mengklik link untuk melihat item. Ini adalah basis kami yang dapat diakses.

Kirimkan daftar dengan elemen <ul>:

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

Buat item daftar menjadi 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 menghadirkan konteks tambahan thumbnail, atau sebagai teks penggantian jika gambar tidak dimuat, atau menyediakan UI lisan untuk pengguna yang mengandalkan teknologi pendukung seperti pembaca layar. Pelajari lebih lanjut dengan Lima aturan emas untuk teks alternatif yang mematuhi kebijakan.

Atribut loading menerima kata kunci lazy sebagai cara untuk memberi sinyal bahwa sumber gambar ini harus diambil hanya saat gambar berada dalam area pandang. Cara ini sangat bagus untuk daftar besar, karena pengguna hanya akan mendownload gambar untuk item yang mereka scroll ke tampilan.

Mendukung preferensi skema warna pengguna

Gunakan color-scheme sebagai tag <meta> untuk memberi tahu browser bahwa halaman Anda menginginkan gaya agen pengguna yang disediakan terang dan gelap. Mode gelap atau mode terang gratis, tergantung bagaimana Anda melihatnya:

<meta name="color-scheme" content="dark light">

Tag meta memberikan sinyal seawal mungkin, sehingga browser dapat memilih warna kanvas default gelap jika pengguna memiliki preferensi tema gelap. Artinya, navigasi antar-halaman situs tidak akan memberikan latar belakang kanvas putih di antara pemuatan. Tema gelap yang mulus di antara pemuatan, jauh lebih menarik di mata.

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. Saya telah mengemas demo dengan gambar dan teks placeholder statis, tetapi jangan ragu untuk mendukungnya dari sumber data favorit Anda.

Menambahkan gaya dengan CSS

Sekarang saatnya CSS mengambil daftar konten umum ini dan mengubahnya menjadi pengalaman. Netflix, App store, dan banyak situs serta aplikasi lainnya menggunakan area scroll horizontal untuk mengemas area pandang dengan kategori dan opsi.

Membuat tata letak scroller

Penting untuk menghindari pemotongan konten dalam tata letak atau bersandar pada pemotongan teks dengan elipsis. Banyak televisi memiliki penggulir media seperti yang satu ini, tetapi terlalu sering menggunakan konten elips. Tata letak ini tidak cocok. Ini juga memungkinkan konten media mengganti ukuran kolom, sehingga membuat 1 tata letak cukup fleksibel untuk menangani banyak kombinasi menarik.

2 baris scroll ditampilkan. Satu tidak memiliki elipsis, yang berarti lebih tinggi dan setiap
judul dapat dibaca sepenuhnya. Satunya lebih pendek dan banyak judul yang terpotong
dengan elipsis.

Penampung memungkinkan penggantian ukuran kolom dengan memberikan ukuran default sebagai properti kustom. Tata letak petak ini memiliki opini 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 khusus ini kemudian digunakan oleh elemen <picture> untuk membuat rasio aspek dasar: sebuah 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 lagi, selesaikan menu barebon dari scroller 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);
  }
}

Menyetel overflow akan menyiapkan <ul> untuk memungkinkan navigasi scroll dan keyboard melalui daftarnya, lalu setiap elemen <li> turunan langsung akan menghapus ::marker-nya dengan mendapatkan jenis tampilan inline-block baru.

Gambar belum responsif, dan langsung keluar dari kotak. Kurangi penggunaan dengan beberapa ukuran, kecocokan, dan gaya batas, serta gradien latar belakang saat pemuatan 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 terhadap konten halaman, serta area permukaan scroll dari tepi ke tepi, sangat penting untuk komponen yang harmonis dan minimal.

Untuk membuat tata letak scroll tepi-ke-tepi yang selaras dengan garis tipografi dan 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 horizontal Hal di atas menunjukkan betapa mudahnya menempatkan container scroll, tetapi ada masalah kompatibilitas yang belum diselesaikan dengannya (namun, telah diperbaiki di Chromium 91 ke atas). Lihat di sini untuk mengetahui sekilas histori, tetapi versi singkatnya adalah padding tidak selalu diperhitungkan dalam tampilan scroll.

Kotak
ditandai di sisi inline ujung item daftar terakhir, yang menunjukkan
padding dan elemen memiliki lebar yang sama seperti untuk membuat perataan yang diinginkan.

Untuk mengelabui browser agar menempatkan padding di akhir scroller, saya akan menargetkan gambar 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);
  }
}

Menggunakan properti logis memungkinkan scroller media untuk berfungsi dalam mode penulisan dan arah dokumen apa pun.

Pengepasan scroll

Container scroll dengan tambahan dapat menjadi area pandang pengepasan dengan satu baris CSS, lalu turunan dapat menentukan bagaimana mereka ingin disejajarkan 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 banyak lagi. Banyak platform video game menggunakan scroller media yang sangat mirip dengan yang ini, sebagai tata letak layar utama yang utama. Fokus adalah momen UX yang besar, bukan hanya sedikit tambahan. Bayangkan menggunakan scroller media ini dari sofa dengan remote, beri interaksi tersebut beberapa peningkatan kecil:

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

Tindakan ini menetapkan gaya garis batas fokus 7px dari kotak, sehingga memberikan ruang yang bagus. Jika pengguna tidak memiliki preferensi gerakan untuk mengurangi gerakan, offset akan ditransisikan, sehingga memberikan gerakan halus ke peristiwa fokus.

Indeks keliling

Pengguna gamepad dan keyboard memerlukan perhatian khusus dalam daftar panjang konten scroll dan opsi ini. Pola umum untuk menyelesaikan masalah ini disebut indeks keliling. Ini terjadi saat penampung item berfokus pada keyboard, tetapi hanya 1 turunan yang diizinkan untuk mempertahankan fokus pada satu waktu. Satu item yang dapat difokuskan pada satu waktu ini dirancang untuk memungkinkan mengabaikan daftar item yang berpotensi panjang, bukan menekan tab sebanyak 50+ kali untuk mencapai akhir.

Ada 300 item dalam scroller pertama demo tersebut. Kita bisa melakukan yang lebih baik daripada membuat mereka melewati 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 memudahkan pengalaman pengguna ini. Berikut cara menggunakannya untuk 3 scroller:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

Demo ini membuat kueri dokumen untuk scroller dan setiap scroller akan memanggil fungsi rovingIndex(). Teruskan elemen rovingIndex() untuk mendapatkan pengalaman keliling, 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 efek ini lebih lanjut, lihat library open source roving-ux.

Rasio aspek

Saat menulis postingan ini, dukungan untuk aspect-ratio berada di belakang flag di Firefox, tetapi tersedia di browser Chromium atau dekoder. Karena tata letak petak scroller media hanya menentukan arah dan spasi, ukuran dapat berubah di dalam kueri media yang menampilkan dukungan rasio aspek. Peningkatan progresif menjadi scroller media yang lebih dinamis.

Kotak
dengan rasio aspek 4:4 akan ditampilkan di samping rasio desain lain yang digunakan antara 16:9
dan 4:3

@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 scroller media akan diupgrade ke ukuran aspect-ratio. Dengan menggunakan draf sintaksis bertingkat, setiap gambar mengubah rasio aspek, bergantung pada apakah itu baris pertama, kedua, atau ketiga. Sintaksis bertingkat juga memungkinkan penetapan beberapa penyesuaian area pandang kecil, bersama logika ukuran lainnya.

Dengan CSS tersebut, karena fitur tersedia di lebih banyak mesin browser, tata letak yang mudah dikelola tetapi lebih menarik secara visual akan dirender.

Mengutamakan pengurangan data

Meskipun teknik berikutnya ini hanya tersedia di belakang flag di Canary, saya ingin berbagi cara menghemat banyak waktu muat halaman dan penggunaan data dengan beberapa baris CSS. Kueri media prefers-reduced-data dari level 5 memungkinkan pertanyaan apakah perangkat dalam status data yang dikurangi, seperti mode penghemat data. Jika ya, saya bisa memodifikasi dokumen, dan dalam hal ini, menyembunyikan gambarnya.

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

Konten masih dapat dijelajahi, tetapi tanpa harus mendownload gambar yang berat. Berikut adalah situs sebelum menambahkan CSS prefers-reduced-data:

(7 permintaan, 100 kb resource dalam 131 md)

ALT_TEXT_HERE

Berikut adalah performa situs setelah menambahkan CSS prefers-reduced-data:

ALT_TEXT_HERE

(71 permintaan, 1,2 mb resource dalam 1,07 dtk)

64 permintaan lebih sedikit, yaitu ~60 gambar dalam area tampilan (pengujian yang dilakukan pada tampilan layar lebar) tab browser ini, peningkatan pemuatan halaman sebesar ~80%, dan 10% data melalui kabel. CSS yang cukup canggih.

Kesimpulan

Sekarang Anda tahu bagaimana saya melakukannya, bagaimana Anda akan?! 🙂

Mari lakukan diversifikasi pendekatan dan pelajari semua cara untuk membangun di web. Buat Codepen atau host demo Anda sendiri, kirim tweet, dan saya akan menambahkannya ke bagian remix Komunitas di bawah.

Sumber

Remix komunitas

Belum ada apa-apa di sini.