Ikhtisar dasar tentang cara membuat komponen tab yang mirip dengan yang ditemukan di aplikasi iOS dan Android.
Dalam postingan ini, saya ingin berbagi pemikiran tentang cara membuat komponen Tab untuk web yang responsif, mendukung banyak input perangkat, dan berfungsi di berbagai browser. Coba demonya.
Jika Anda lebih suka video, berikut versi YouTube postingan ini:
Ringkasan
Tab adalah komponen yang umum dari sistem desain, tetapi dapat memiliki banyak bentuk dan
bentuk. Pertama, ada tab desktop yang dibuat berdasarkan elemen <frame>
, dan sekarang kita memiliki
komponen seluler mentega yang menganimasikan konten berdasarkan properti fisika.
Mereka semua mencoba untuk melakukan hal yang sama: menghemat ruang.
Saat ini, hal penting dari pengalaman pengguna tab adalah area navigasi tombol yang mengubah visibilitas konten dalam frame tampilan. Banyak area konten yang berbeda memiliki ruang yang sama, tetapi ditampilkan secara bersyarat berdasarkan tombol yang dipilih di navigasi.
![kolase cukup rumit karena banyaknya gaya yang diterapkan web pada konsep komponen](https://web.dev/static/articles/building/a-tabs-component/image/the-collage-is-quite-chao-b6f8cd38f8ddd.png?authuser=6&hl=id)
Taktik Web
Secara keseluruhan, saya menemukan komponen ini cukup mudah untuk dibuat, berkat beberapa fitur platform web yang penting:
scroll-snap-points
untuk interaksi keyboard dan geser yang elegan dengan posisi scroll berhenti yang sesuai- Deep link melalui hash URL untuk browser yang menangani anchor scroll dalam halaman dan dukungan berbagi
- Dukungan pembaca layar dengan markup elemen
<a>
danid="#hash"
prefers-reduced-motion
untuk mengaktifkan transisi crossfade dan scroll instan dalam halaman- Fitur web
@scroll-timeline
dalam draf untuk menggarisbawahi dan mengubah warna tab yang dipilih secara dinamis
HTML
Pada dasarnya, UX di sini adalah: mengklik link, membuat URL merepresentasikan status halaman bertingkat, lalu melihat pembaruan area konten saat browser men-scroll ke elemen yang cocok.
Terdapat beberapa anggota konten struktural di dalamnya: link dan :target
. Kita
memerlukan daftar link, <nav>
yang cocok, dan daftar elemen <article>
, yang cocok untuk <section>
. Setiap {i>hash <i}link akan cocok dengan bagian, memungkinkan
browser men-scroll berbagai hal melalui anchoring.
Misalnya, mengklik link akan otomatis memfokuskan artikel :target
di
Chrome 89, tanpa JS. Kemudian, pengguna dapat men-scroll konten artikel dengan
perangkat input seperti biasa. Ini adalah konten pelengkap, seperti yang ditunjukkan pada
markup.
Saya menggunakan markup berikut untuk mengatur tab:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
Saya dapat membuat koneksi antara elemen <a>
dan <article>
dengan properti href
dan id
seperti ini:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
Kemudian saya mengisi artikel dengan berbagai jenis {i>lorem<i}, dan link-nya dengan kombinasi panjang dan kumpulan gambar judul. Dengan konten yang akan dikerjakan, kita bisa memulai menata letak.
Tata letak scroll
Ada 3 jenis area scroll dalam komponen ini:
- Navigasi (merah muda) dapat di-scroll secara horizontal
- Area konten (biru) dapat di-scroll secara horizontal
- Setiap item artikel (hijau) dapat di-scroll secara vertikal.
![3 kotak warna-warni dengan panah arah yang cocok dengan warna yang menguraikan area scroll dan menunjukkan arah scroll.](https://web.dev/static/articles/building/a-tabs-component/image/3-colorful-boxes-color-m-da0de23b13551.png?authuser=6&hl=id)
Ada 2 jenis elemen berbeda yang terlibat dalam {i>scroll<i}:
- Jendela
Kotak dengan dimensi yang ditentukan yang memiliki gaya propertioverflow
. - Permukaan besar
Dalam tata letak ini, adalah penampung daftar: link navigasi, artikel bagian, dan konten artikel.
Tata letak <snap-tabs>
Tata letak tingkat atas yang saya pilih adalah {i>flex<i} (Flexbox). Saya menetapkan arah ke
column
, sehingga header dan bagian diurutkan secara vertikal. Ini adalah jendela scroll pertama kita, dan jendela ini menyembunyikan semua dengan overflow tersembunyi. Header dan bagian akan segera menggunakan overscroll, sebagai zona individual.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
Menunjuk kembali ke diagram 3 scroll penuh warna:
<header>
sekarang disiapkan untuk menjadi container scroll (merah muda).<section>
disiapkan untuk menjadi penampung scroll (blue).
Frame yang telah saya tandai di bawah dengan VisBug membantu kita melihat jendela yang dibuat container scroll.
![elemen {i>header<i} dan bagian memiliki overlay hotpink di atasnya, yang menguraikan ruang yang dibutuhkan dalam komponen](/static/articles/building/a-tabs-component/image/the-header-section-eleme-dd313d7eb1453.png)
Tata letak tab <header>
Tata letak berikutnya hampir sama: saya menggunakan {i>flex<i} untuk membuat pengurutan vertikal.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
harus bergerak secara horizontal bersama grup link, dan
tata letak header ini membantu menetapkan tahap tersebut. Tidak ada elemen yang diposisikan dengan mutlak di sini!
![elemen nav dan span.indicator memiliki overlay hotpink di atasnya, yang menguraikan ruang yang diperlukan dalam komponen](https://web.dev/static/articles/building/a-tabs-component/image/the-nav-spanindicator-e-eddaf5b04df39.png?authuser=6&hl=id)
Berikutnya, gaya scroll. Ternyata kita bisa berbagi gaya scroll
antara 2 area scroll horizontal (header dan bagian), jadi saya membuat class
utilitas, .scroll-snap-x
.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
Setiap memerlukan overflow pada sumbu x, pembatasan scroll untuk menangkap overscroll, scrollbar tersembunyi untuk perangkat sentuh, dan terakhir scroll-snap untuk mengunci area presentasi konten. Urutan tab keyboard kami dapat diakses dan panduan interaksi apa pun berfokus secara alami. Penampung snap scroll juga mendapatkan interaksi gaya carousel yang bagus dari keyboard mereka.
Tata letak <nav>
header tab
Link navigasi harus ditata dalam baris, tanpa jeda baris, di tengah secara vertikal, dan setiap item link harus pas ke penampung scroll-snap. Kerja cepat untuk CSS 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
Setiap gaya dan ukuran link itu sendiri, sehingga tata letak navigasi hanya perlu menentukan arah dan alur. Lebar unik pada item navigasi membuat transisi antar-tab menyenangkan karena indikator menyesuaikan lebarnya dengan target baru. Bergantung pada jumlah elemen di sini, browser akan merender scrollbar atau tidak.
![elemen navigasi memiliki overlay hotpink di atasnya, menguraikan ruang yang diambil dalam komponen serta tempat mereka meluap](https://web.dev/static/articles/building/a-tabs-component/image/the-elements-the-nav-h-c8efe2b10b412.png?authuser=6&hl=id)
Tata letak tab <section>
Bagian ini adalah item fleksibel dan harus menjadi konsumen ruang yang dominan. Anda
juga perlu membuat kolom untuk menempatkan artikel. Sekali lagi, kerja cepat
untuk CSS 2021! block-size: 100%
merentangkan elemen ini untuk mengisi
induk sebanyak mungkin, lalu untuk tata letaknya sendiri, elemen ini akan membuat serangkaian
kolom yang berukuran 100%
selebar induk. Persentase bekerja dengan baik di sini
karena kita telah menulis batasan kuat pada induk.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
Ini seolah-olah kita mengatakan "luaskan secara vertikal sebanyak mungkin, dengan cara yang memaksa"
(ingat header yang kita tetapkan ke flex-shrink: 0
: ini adalah pertahanan terhadap
push ekspansi ini), yang menetapkan tinggi baris untuk satu set kolom dengan tinggi penuh. Gaya
auto-flow
memberi tahu grid untuk selalu menata letak turunan dalam garis
horizontal, tanpa penggabungan, persis seperti yang kita inginkan; untuk meluberkan jendela induk.
![elemen artikel memiliki overlay hotpink di atasnya, menguraikan ruang yang diambil dalam komponen dan tempat mereka meluap](https://web.dev/static/articles/building/a-tabs-component/image/the-article-elements-hot-924ae524ee8fb.png?authuser=6&hl=id)
Kadang-kadang aku merasa kesulitan untuk memikirkannya! Elemen bagian ini pas ke dalam kotak, tetapi juga membuat satu set kotak. Saya harap visualisasi dan penjelasannya dapat membantu.
Tata letak tab <article>
Pengguna harus dapat men-scroll konten artikel, dan scrollbar hanya akan muncul jika ada tambahan. Elemen-elemen artikel ini berada dalam posisi yang rapi. Keduanya secara bersamaan merupakan induk scroll dan turunan scroll. Browser benar-benar menangani beberapa interaksi sentuh, mouse, dan keyboard yang rumit untuk kita di sini.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
Saya memilih untuk menempatkan artikel dalam scroller induknya. Saya sangat menyukai cara item link navigasi dan elemen artikel disesuaikan dengan inline-start dari penampung scroll-nya masing-masing. Terlihat dan terasa seperti hubungan yang harmonis.
![elemen artikel dan elemen turunannya memiliki overlay hotpink di atasnya, yang menguraikan ruang yang diambil dalam komponen dan arah luapannya](https://web.dev/static/articles/building/a-tabs-component/image/the-article-element-its-8afcb8a6817ff.png?authuser=6&hl=id)
Artikel ini adalah turunan petak, dan ukurannya telah ditentukan sebagai area area pandang yang ingin kita berikan UX scroll. Artinya, saya tidak memerlukan gaya tinggi atau lebar di sini, saya hanya perlu mendefinisikan cara menambahkan elemen ke atas. Saya menetapkan overflow-y ke otomatis, lalu menangkap interaksi scroll dengan properti perilaku overscroll yang praktis.
Rekap 3 area scroll
Di setelan sistem, saya memilih "selalu tampilkan scrollbar". Menurut saya, tata letak perlu diaktifkan dua kali dengan mengaktifkan setelan ini, karena saya harus meninjau tata letak dan orkestrasi scroll.
![ketiga scrollbar disetel untuk ditampilkan, yang kini menggunakan ruang tata letak, dan komponen kita masih terlihat bagus](https://web.dev/static/articles/building/a-tabs-component/image/the-3-scrollbars-are-set-ca02ac51f046d.png?authuser=6&hl=id)
Menurut saya, melihat gutter scrollbar dalam komponen ini membantu menunjukkan dengan jelas lokasi area scroll, arah yang didukungnya, dan cara interaksinya satu sama lain. Pertimbangkan bagaimana setiap frame jendela scroll ini juga merupakan induk fleksibel atau petak ke tata letak.
DevTools dapat membantu kita memvisualisasikan:
![area scroll memiliki overlay alat grid dan flexbox, yang menguraikan ruang yang diambil dalam komponen dan arah menu luapan](https://web.dev/static/articles/building/a-tabs-component/image/the-scroll-areas-grid-f-79f0ae5839bcc.png?authuser=6&hl=id)
Tata letak scroll sudah lengkap: snap, deep linkable, dan akses keyboard. Fondasi yang kuat untuk peningkatan kualitas UX, gaya, dan kesenangan.
Sorotan fitur
Turunan yang diikat scroll mempertahankan posisi terkuncinya selama perubahan ukuran. Artinya, JavaScript tidak perlu menampilkan apa pun saat pemutaran perangkat atau perubahan ukuran browser. Cobalah di Mode Perangkat Chromium DevTools dengan memilih mode apa pun selain Responsive, lalu mengubah ukuran frame perangkat. Perhatikan bahwa elemen tetap terlihat dan terkunci dengan kontennya. Fitur ini telah tersedia sejak Chromium mengupdate implementasinya agar sesuai dengan spesifikasi. Berikut postingan blog tentangnya.
Animasi
Tujuan pekerjaan animasi di sini adalah untuk secara jelas menghubungkan interaksi dengan masukan UI. Hal ini akan memandu atau membantu pengguna menemukan semua konten (semoga) dengan mulus. Saya akan menambahkan {i>motion <i} dengan tujuan dan dengan syarat. Pengguna kini dapat menentukan preferensi gerakan dalam sistem operasi mereka, dan saya benar-benar menikmati respons terhadap preferensi mereka di antarmuka saya.
Saya akan menautkan garis bawah tab dengan posisi scroll artikel. {i>Snapping<i} bukan hanya keselarasan yang indah, tetapi juga menambatkan awal dan akhir animasi.
Tindakan ini akan mempertahankan <nav>
, yang bertindak seperti
peta mini, yang tetap terhubung ke konten.
Kita akan memeriksa preferensi gerakan pengguna baik dari CSS maupun JS. Ada beberapa tempat bagus yang perlu dipertimbangkan!
Perilaku scroll
Ada peluang untuk meningkatkan perilaku gerakan :target
dan
element.scrollIntoView()
. Secara default, ini bersifat instan. Browser hanya menetapkan
posisi scroll. Nah, bagaimana jika kita ingin beralih ke
posisi scroll itu, alih-alih berkedip di sana?
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
Karena kita memperkenalkan gerakan di sini, dan gerakan yang tidak dikontrol pengguna (seperti men-scroll), kita hanya menerapkan gaya ini jika pengguna tidak memiliki preferensi dalam sistem operasinya terkait gerakan yang dikurangi. Dengan cara ini, kami hanya memperkenalkan gerakan gulir untuk orang-orang yang menyukainya.
Indikator tab
Tujuan animasi ini adalah untuk membantu mengaitkan indikator dengan status
konten. Saya memutuskan untuk mewarnai gaya border-bottom
crossfade untuk pengguna
yang lebih menyukai gerakan yang dikurangi, dan scroll tertaut animasi geser + warna fade [memudarkan warna]
bagi pengguna yang setuju dengan gerakan.
Di Chromium Devtools, saya dapat beralih preferensi dan mendemonstrasikan 2 gaya transisi yang berbeda. Saya sangat senang ketika membangunnya.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
Saya menyembunyikan .snap-indicator
saat pengguna lebih memilih gerakan yang dikurangi karena saya tidak
memerlukannya lagi. Lalu, saya menggantinya dengan gaya border-block-end
dan
transition
. Perhatikan juga di interaksi tab bahwa item navigasi aktif tidak
hanya memiliki sorotan garis bawah merek, tetapi warna teksnya juga lebih gelap. Elemen
aktif memiliki kontras warna teks yang lebih tinggi dan aksen bawah cahaya yang cerah.
Hanya beberapa baris CSS tambahan yang akan membuat seseorang merasa diperhatikan (dalam arti bahwa kita menghormati preferensi gerakan mereka dengan penuh pertimbangan). Saya menyukainya.
@scroll-timeline
Di bagian atas, saya menunjukkan cara menangani gaya crossfade gerakan yang dikurangi, dan di bagian ini, saya akan menunjukkan cara menautkan indikator dan area scroll bersama-sama. Berikut adalah beberapa hal eksperimental yang menyenangkan. Saya harap Anda bersemangat seperti saya.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
Pertama-tama, saya memeriksa preferensi gerakan
pengguna dari JavaScript. Jika hasil dari
ini adalah false
, yang berarti pengguna lebih memilih gerakan yang dikurangi, kita tidak akan menjalankan
efek gerakan scroll yang menautkan.
if (motionOK) {
// motion based animation code
}
Pada saat penulisan ini, dukungan browser untuk
@scroll-timeline
tidak ada. Ini adalah
spesifikasi draf dengan hanya
implementasi eksperimental. Namun, ini memiliki polyfill, yang saya gunakan dalam demo ini.
ScrollTimeline
Meskipun CSS dan JavaScript dapat membuat linimasa scroll, saya memilih JavaScript agar dapat menggunakan pengukuran elemen langsung dalam animasi.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
Saya ingin 1 hal mengikuti posisi scroll orang lain, dan dengan membuat
ScrollTimeline
, saya menentukan driver link scroll, scrollSource
.
Biasanya animasi di web dijalankan pada tick jangka waktu global, tetapi dengan sectionScrollTimeline
kustom di memori, saya dapat mengubah semua itu.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
Sebelum masuk ke keyframe animasi, saya pikir penting untuk
menunjukkan pengikut scrolling, tabindicator
, akan dianimasikan berdasarkan
linimasa kustom, scroll bagian kita. Tindakan ini melengkapi penautan, tetapi
tidak memiliki bahan terakhir yaitu titik stateful untuk dianimasikan, yang juga dikenal sebagai
keyframe.
Keyframe dinamis
Ada cara CSS deklaratif murni yang sangat efektif untuk menganimasikan dengan
@scroll-timeline
, tetapi animasi yang saya pilih terlalu dinamis. Tidak ada
cara untuk melakukan transisi antara lebar auto
, dan tidak ada cara untuk membuat
jumlah keyframe secara dinamis berdasarkan panjang turunan.
Namun, JavaScript mengetahui cara mendapatkan informasi tersebut, jadi kita akan melakukan iterasi pada turunan itu sendiri dan mengambil nilai yang dihitung saat runtime:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
Untuk setiap tabnavitem
, uraikan posisi offsetLeft
dan tampilkan string
yang menggunakannya sebagai nilai translateX
. Tindakan ini membuat 4 transformasi keyframe untuk
animasi. Hal yang sama dilakukan untuk lebar. Setiap orang ditanya berapa lebar dinamisnya, lalu digunakan sebagai nilai keyframe.
Berikut contoh output, berdasarkan preferensi font dan browser saya:
Keyframe TranslateX:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
Keyframe Lebar:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
Untuk meringkas strategi, indikator tab kini akan dianimasikan di 4 keyframe, bergantung pada posisi snap scroll dari scroller bagian. Titik snap menciptakan batas yang jelas antara keyframe kita dan benar-benar menambah nuansa animasi yang disinkronkan.
![tab aktif dan tab tidak aktif ditampilkan dengan overlay VisBug yang menampilkan skor kontras yang lulus untuk keduanya](https://web.dev/static/articles/building/a-tabs-component/image/active-tab-inactive-tab-9604191ea7007.png?authuser=6&hl=id)
Pengguna menggerakkan animasi dengan interaksi mereka, melihat lebar dan posisi indikator berubah dari satu bagian ke bagian berikutnya, melacak secara sempurna dengan scroll.
Anda mungkin tidak menyadarinya, tetapi saya sangat bangga dengan transisi warna saat item navigasi yang ditandai dipilih.
Warna abu-abu muda yang tidak dipilih akan tampak lebih terdorong saat item yang disorot memiliki kontras yang lebih besar. Mentransisikan warna untuk teks adalah hal yang umum dilakukan, seperti saat mengarahkan kursor dan saat dipilih, tetapi cara selanjutnya adalah mentransisikan warna tersebut saat men-scroll, yang disinkronkan dengan indikator garis bawah.
Begini cara saya melakukannya:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
Setiap link navigasi tab memerlukan animasi warna baru ini, yang melacak linimasa scroll yang sama dengan indikator garis bawah. Saya menggunakan linimasa yang sama seperti sebelumnya: karena perannya adalah untuk memunculkan tanda centang saat men-scroll, kita dapat menggunakan tanda centang tersebut dalam jenis animasi apa pun yang kita inginkan. Seperti yang saya lakukan sebelumnya, saya membuat 4 keyframe di loop, dan menampilkan warna.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
Keyframe dengan warna var(--text-active-color)
menandai link, dan jika tidak, warna teks standar. Loop bertingkat di sana membuatnya relatif
lugas, karena loop luar adalah setiap item navigasi, dan loop dalam adalah keyframe pribadi setiap
item navigasi. Saya memeriksa apakah elemen loop luar sama dengan
loop dalam, dan menggunakannya untuk mengetahui kapan dipilih.
Saya sangat senang saat menulis ini. Banyak sekali.
Lebih banyak lagi peningkatan JavaScript
Perlu diingat bahwa inti dari yang saya tunjukkan di sini berfungsi tanpa JavaScript. Dengan demikian, mari kita lihat bagaimana kita dapat meningkatkannya saat JS tersedia.
Deep link
Deep link lebih merupakan istilah seluler, tetapi tujuan dari deep link
di sini adalah dengan tab yang memungkinkan Anda membagikan URL secara langsung ke konten tab. Browser akan membuka ID yang cocok dengan hash URL dalam halaman. Saya menemukan
pengendali onload
ini membuat efek di seluruh platform.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
Scroll akhiri sinkronisasi
Pengguna kami tidak selalu mengklik atau menggunakan keyboard, terkadang mereka hanya men-scroll bebas, seperti yang seharusnya. Saat scroller bagian berhenti men-scroll, di mana pun scroller terbuka harus dicocokkan di menu navigasi atas.
Berikut cara menunggu scroll berakhir:
js
tabsection.addEventListener('scroll', () => {
clearTimeout(tabsection.scrollEndTimer);
tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100);
});
Setiap kali bagian di-scroll, hapus waktu tunggu bagian jika ada, dan mulai yang baru. Saat bagian berhenti di-scroll, jangan hapus waktu tunggu, dan aktifkan 100 md setelah beristirahat. Ketika dipicu, panggil fungsi yang akan mencari tahu di mana pengguna berhenti.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
Dengan asumsi bahwa scroll telah diikat, membagi posisi scroll saat ini dari lebar area scroll akan menghasilkan bilangan bulat, bukan desimal. Kemudian saya mencoba mengambil navitem dari cache melalui indeks yang dihitung ini, dan jika menemukan sesuatu, saya mengirimkan kecocokan tersebut untuk diaktifkan.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
Menyetel tab aktif dimulai dengan menghapus tab yang sedang aktif, lalu memberikan
atribut status aktif ke item navigasi yang masuk. Panggilan ke scrollIntoView()
memiliki interaksi yang menyenangkan dengan CSS yang perlu diperhatikan.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
Dalam CSS utilitas snap scroll horizontal, kami telah
menyusun bertingkat kueri media yang menerapkan
scroll smooth
jika pengguna toleran terhadap gerakan. JavaScript dapat dengan bebas melakukan
panggilan untuk men-scroll elemen ke tampilan, dan CSS dapat mengelola UX secara deklaratif.
Permainan kecil yang kadang-kadang cukup menyenangkan.
Kesimpulan
Sekarang Anda tahu bagaimana saya melakukannya, bagaimana Anda akan?! Inilah arsitektur komponen yang menyenangkan! Siapa yang akan membuat versi pertama dengan slot di framework favorit mereka? 🙂
Mari lakukan diversifikasi pendekatan dan pelajari semua cara untuk membangun di web. Buat Glitch, tweet me versi Anda, dan saya akan menambahkannya ke bagian Remix Komunitas di bawah.
Remix komunitas
- @devnook, @rob_dodson, dan @DasSurma dengan Komponen Web: article.
- @jhvanderschee dengan tombol: Codepen.