Ringkasan dasar tentang cara membuat komponen breadcrumb yang responsif dan mudah diakses bagi pengguna untuk menavigasi situs Anda.
Dalam postingan ini, saya ingin membagikan pemikiran tentang cara membuat komponen breadcrumb. Coba demo.
Jika Anda lebih suka video, berikut versi YouTube dari postingan ini:
Ringkasan
Komponen breadcrumb menunjukkan posisi pengguna dalam hierarki situs. Namanya berasal dari kisah Hansel dan Gretel, yang menjatuhkan remah-remah di belakang mereka di beberapa hutan gelap dan dapat menemukan jalan pulang dengan melacak remah-remah ke belakang.
Breadcrumb dalam postingan ini bukan breadcrumb
standar,
tetapi mirip breadcrumb. Fungsi ini menawarkan fungsi tambahan dengan menempatkan halaman
sejenis langsung ke navigasi dengan <select>
, sehingga memungkinkan akses
multi-tingkat.
UX Latar Belakang
Dalam video demo komponen di atas, kategori placeholder adalah genre
video game. Jejak ini dibuat dengan membuka jalur berikut: home »
rpg » indie » on sale
, seperti yang ditunjukkan di bawah.
Komponen breadcrumb ini akan memungkinkan pengguna untuk menelusuri hierarki informasi ini; melompat ke cabang dan memilih halaman dengan cepat dan akurat.
Arsitektur informasi
Menurut saya, sebaiknya Anda memikirkannya dalam hal koleksi dan item.
Koleksi
Koleksi adalah array opsi yang dapat dipilih. Dari halaman beranda prototipe breadcrumb postingan ini, koleksinya adalah FPS, RPG, brawler, dungeon crawler, olahraga, dan teka-teki.
Item
Video game adalah item, koleksi tertentu juga dapat berupa item jika mewakili koleksi lain. Misalnya, RPG adalah item dan koleksi yang valid. Jika item, pengguna berada di halaman koleksi tersebut. Misalnya, subkategori tersebut berada di halaman RPG, yang menampilkan daftar game RPG, termasuk subkategori tambahan AAA, Indie, dan Self Published.
Dalam istilah ilmu komputer, komponen breadcrumb ini mewakili array multidimensi:
const rawBreadcrumbData = {
"FPS": {...},
"RPG": {
"AAA": {...},
"indie": {
"new": {...},
"on sale": {...},
"under 5": {...},
},
"self published": {...},
},
"brawler": {...},
"dungeon crawler": {...},
"sports": {...},
"puzzle": {...},
}
Aplikasi atau situs Anda akan memiliki arsitektur informasi (IA) kustom yang membuat array multidimensi yang berbeda, tetapi saya harap konsep halaman landing koleksi dan penelusuran hierarki juga dapat masuk ke breadcrumb Anda.
Tata letak
Markup
Komponen yang baik dimulai dengan HTML yang sesuai. Di bagian berikutnya, saya akan membahas pilihan markup dan pengaruhnya terhadap komponen secara keseluruhan.
Skema gelap dan terang
<meta name="color-scheme" content="dark light">
Tag meta color-scheme
dalam cuplikan
di atas memberi tahu browser bahwa halaman ini menginginkan gaya browser
terang dan gelap. Contoh breadcrumb tidak menyertakan CSS apa pun untuk skema warna ini,
sehingga breadcrumb akan menggunakan warna default yang disediakan oleh browser.
Elemen navigasi
<nav class="breadcrumbs" role="navigation"></nav>
Sebaiknya gunakan elemen
<nav>
untuk navigasi situs, yang memiliki peran
navigasi ARIA implisit.
Dalam pengujian, saya melihat bahwa memiliki atribut role
mengubah cara pembaca layar berinteraksi dengan elemen, yang sebenarnya diumumkan sebagai navigasi, sehingga saya memilih untuk menambahkannya.
Ikon
Saat ikon diulang di halaman, elemen
<use>
SVG
berarti Anda dapat menentukan path
sekali, dan menggunakannya untuk semua instance
ikon. Hal ini mencegah informasi jalur yang sama diulang, sehingga menyebabkan
dokumen yang lebih besar dan potensi inkonsistensi jalur.
Untuk menggunakan teknik ini, tambahkan elemen SVG tersembunyi ke halaman dan gabungkan ikon
dalam elemen <symbol>
dengan ID unik:
<svg style="display: none;">
<symbol id="icon-home">
<title>A home icon</title>
<path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
</symbol>
<symbol id="icon-dropdown-arrow">
<title>A down arrow</title>
<path d="M19 9l-7 7-7-7"/>
</symbol>
</svg>
Browser membaca HTML SVG, memasukkan informasi ikon ke dalam memori, dan melanjutkan dengan bagian halaman lainnya yang mereferensikan ID untuk penggunaan tambahan ikon, seperti ini:
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<use href="#icon-home" />
</svg>
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<use href="#icon-dropdown-arrow" />
</svg>
Tentukan sekali, gunakan sebanyak yang Anda inginkan, dengan dampak performa halaman minimal
dan gaya visual yang fleksibel. Perhatikan bahwa aria-hidden="true"
ditambahkan ke elemen SVG.
Ikon tidak berguna bagi pengguna yang hanya mendengarkan konten saat menjelajahi. Menyembunyikannya
dari pengguna tersebut akan mencegah mereka menambahkan derau yang tidak perlu.
Link terpisah .crumb
Di sinilah perbedaan antara breadcrumb tradisional dan breadcrumb dalam komponen ini.
Biasanya, ini hanya akan menjadi link <a>
, tetapi saya telah menambahkan UX traversal dengan
pilihan yang disamarkan. Class .crumb
bertanggung jawab untuk menata letak link dan
ikon, sedangkan .crumbicon
bertanggung jawab untuk menumpuk ikon dan elemen
pilihan secara bersamaan. Saya menyebutnya link terpisah karena fungsinya sangat mirip dengan tombol terpisah, tetapi untuk navigasi halaman.
<span class="crumb">
<a href="#sub-collection-b">Category B</a>
<span class="crumbicon">
<svg>...</svg>
<select class="disguised-select" title="Navigate to another category">
<option>Category A</option>
<option selected>Category B</option>
<option>Category C</option>
</select>
</span>
</span>
Link dan beberapa opsi tidak ada yang istimewa, tetapi menambahkan lebih banyak fungsi ke
breadcrumb sederhana. Menambahkan title
ke elemen <select>
akan membantu pengguna pembaca
layar, memberi mereka informasi tentang tindakan tombol. Namun, fitur ini
juga memberikan bantuan yang sama kepada semua orang, Anda akan melihatnya di bagian depan dan tengah
di iPad. Satu atribut memberikan konteks tombol kepada banyak pengguna.
Dekorasi pemisah
<span class="crumb-separator" aria-hidden="true">→</span>
Pemisah bersifat opsional, menambahkan satu pemisah juga berfungsi dengan baik (lihat contoh ketiga dalam video
di atas). Kemudian, saya memberikan setiap aria-hidden="true"
karena bersifat dekoratif dan bukan
sesuatu yang perlu diumumkan oleh pembaca layar.
Properti gap
, yang akan dibahas berikutnya, membuat spasi ini menjadi mudah.
Gaya
Karena warna menggunakan warna sistem, sebagian besar warna ini adalah celah dan tumpukan untuk gaya.
Arah dan alur tata letak
Elemen navigasi utama nav.breadcrumbs
menetapkan properti kustom cakupan
untuk digunakan oleh turunan, dan jika tidak, menetapkan tata letak horizontal yang sejajar
secara vertikal. Hal ini memastikan bahwa crumbs, pembagi, dan ikon sejajar.
.breadcrumbs {
--nav-gap: 2ch;
display: flex;
align-items: center;
gap: var(--nav-gap);
padding: calc(var(--nav-gap) / 2);
}
Setiap .crumb
juga menetapkan tata letak horizontal yang sejajar secara vertikal dengan beberapa
celah, tetapi secara khusus menargetkan turunan link-nya dan menentukan gaya
white-space: nowrap
. Hal ini penting untuk breadcrumb multi-kata karena kita tidak
ingin breadcrumb tersebut menjadi multi-baris. Nanti dalam postingan ini, kita akan menambahkan gaya untuk menangani
overflow horizontal yang disebabkan oleh properti white-space
ini.
.crumb {
display: inline-flex;
align-items: center;
gap: calc(var(--nav-gap) / 4);
& > a {
white-space: nowrap;
&[aria-current="page"] {
font-weight: bold;
}
}
}
aria-current="page"
ditambahkan untuk membantu link halaman saat ini tampil beda dari
link lainnya. Pengguna pembaca layar tidak hanya akan memiliki indikator yang jelas bahwa link tersebut
adalah untuk halaman saat ini, tetapi kami juga telah menata gaya elemen secara visual untuk membantu pengguna yang dapat melihat
mendapatkan pengalaman pengguna yang serupa.
Komponen .crumbicon
menggunakan petak untuk menumpuk ikon SVG dengan elemen <select>
yang "hampir
tidak terlihat".
.crumbicon {
--crumbicon-size: 3ch;
display: grid;
grid: [stack] var(--crumbicon-size) / [stack] var(--crumbicon-size);
place-items: center;
& > * {
grid-area: stack;
}
}
Elemen <select>
adalah elemen terakhir di DOM, sehingga berada di atas data sebelumnya,
dan interaktif. Tambahkan gaya opacity: .01
agar elemen masih dapat digunakan,
dan hasilnya adalah kotak pilih yang sangat sesuai dengan bentuk ikon.
Ini adalah cara yang bagus untuk menyesuaikan tampilan elemen <select>
sekaligus
mempertahankan fungsi bawaan.
.disguised-select {
inline-size: 100%;
block-size: 100%;
opacity: .01;
font-size: min(100%, 16px); /* Defaults to 16px; fixes iOS zoom */
}
Tambahan
Breadcrumb harus dapat mewakili jalur yang sangat panjang. Saya suka mengizinkan hal-hal keluar dari layar secara horizontal, jika sesuai, dan saya merasa komponen breadcrumb ini memenuhi syarat dengan baik.
.breadcrumbs {
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x proximity;
scroll-padding-inline: calc(var(--nav-gap) / 2);
& > .crumb:last-of-type {
scroll-snap-align: end;
}
@supports (-webkit-hyphens:none) { & {
scroll-snap-type: none;
}}
}
Gaya overflow menyiapkan UX berikut:
- Scroll horizontal dengan pembatasan overscroll.
- Padding scroll horizontal.
- Satu titik snap pada crumb terakhir. Artinya, saat halaman dimuat, crumb pertama akan dimuat dan terlihat.
- Menghapus titik snap dari Safari, yang mengalami kesulitan dengan kombinasi efek snap dan scroll horizontal.
Kueri media
Salah satu penyesuaian halus untuk area pandang yang lebih kecil adalah menyembunyikan label "Beranda", sehingga hanya meninggalkan ikon:
@media (width <= 480px) {
.breadcrumbs .home-label {
display: none;
}
}
Aksesibilitas
Gerakan
Tidak ada banyak gerakan dalam komponen ini, tetapi dengan menggabungkan
transisi dalam pemeriksaan prefers-reduced-motion
, kita dapat mencegah gerakan yang tidak diinginkan.
@media (prefers-reduced-motion: no-preference) {
.crumbicon {
transition: box-shadow .2s ease;
}
}
Tidak ada gaya lain yang perlu diubah, efek pengarahan kursor dan fokus sangat baik
dan bermakna tanpa transition
, tetapi jika gerakan tidak masalah, kita akan menambahkan transisi
halus ke interaksi.
JavaScript
Pertama, terlepas dari jenis router yang Anda gunakan di situs atau aplikasi,
saat pengguna mengubah breadcrumb, URL perlu diperbarui dan pengguna
akan melihat halaman yang sesuai. Kedua, untuk menormalisasi pengalaman pengguna, pastikan
tidak ada navigasi yang tidak terduga saat pengguna hanya menjelajahi opsi
<select>
.
Dua ukuran pengalaman pengguna penting yang akan ditangani oleh JavaScript: pilih telah
berubah dan pencegahan pengaktifan peristiwa perubahan <select>
yang cepat.
Pencegahan peristiwa yang cepat diperlukan karena penggunaan elemen <select>
. Di Windows Edge, dan mungkin juga browser lainnya, peristiwa changed
yang dipilih akan diaktifkan saat pengguna menjelajahi opsi dengan keyboard. Itulah sebabnya saya
menyebutnya eager, karena pengguna hanya memilih opsi secara pseudo, seperti pengarahan kursor
atau fokus, tetapi belum mengonfirmasi pilihan dengan enter
atau click
. Peristiwa eager
membuat fitur perubahan kategori komponen ini tidak dapat diakses, karena
membuka kotak pilih dan hanya menjelajahi item akan memicu peristiwa dan
mengubah halaman, sebelum pengguna siap.
Peristiwa perubahan <select>
yang lebih baik
const crumbs = document.querySelectorAll('.breadcrumbs select')
const allowedKeys = new Set(['Tab', 'Enter', ' '])
const preventedKeys = new Set(['ArrowUp', 'ArrowDown'])
// watch crumbs for changes,
// ensures it's a full value change, not a user exploring options via keyboard
crumbs.forEach(nav => {
let ignoreChange = false
nav.addEventListener('change', e => {
if (ignoreChange) return
// it's actually changed!
})
nav.addEventListener('keydown', ({ key }) => {
if (preventedKeys.has(key))
ignoreChange = true
else if (allowedKeys.has(key))
ignoreChange = false
})
})
Strategi untuk ini adalah dengan memantau peristiwa keyboard down di setiap elemen
<select>
dan menentukan apakah tombol yang ditekan adalah konfirmasi navigasi (Tab
atau
Enter
) atau navigasi spasial (ArrowUp
atau ArrowDown
). Dengan determinasi
ini, komponen dapat memutuskan untuk menunggu atau melanjutkan, saat peristiwa untuk
elemen <select>
diaktifkan.
Kesimpulan
Setelah Anda tahu cara saya melakukannya, bagaimana Anda melakukannya‽ 🙂
Mari kita diversifikasi pendekatan dan pelajari semua cara untuk mem-build di web. Buat demo, tweet link-nya, dan saya akan menambahkannya ke bagian remix komunitas di bawah.
Remix komunitas
- Tux Solbakk sebagai komponen web: demo dan kode