itu<select>
Suatu item adalah konsep yang cukup jelas: fokus pada item tersebut untuk mengungkapkan sekumpulan<option>
Dapat ditentukan sebagai nilai masukan. Ini adalah pola yang bagus dan saya tidak menyarankan untuk mengubahnya. Namun, saya senang mengutak-atik berbagai hal dan menemukan cara menarik untuk berkonversi<select>
Untuk semacam dial — di mana opsi dipilih dengan menggesernya ke posisinya, tidak jauh berbeda dengan kunci kombinasi atau pemilih tanggal di iOS. Siapapun yang telah berkembang<select>
Memilih Negara Mengetahui betapa menyakitkannya daftar yang panjang, dan ini mungkin salah satu cara untuk mencegahnya.
Inilah yang saya bicarakan:
Desain diketahui<select>
Mempelajari CSS sama sekali tidak mudah. Tapi inilah triknya:Kami tidak bekerja dengan Tidak, kami tidak akan melakukan hal seperti membangun
<section class=scroll-container>
<label for="madrid" class="scroll-item">
Madrid
<abbr>MAD</abbr>
<input id="madrid" type="radio" name="items">
</label>
<label for="malta" class="scroll-item">
Malta
<abbr>MLA</abbr>
<input id="malta" type="radio" name="items">
</label>
<!-- etc. -->
</section>
Apa yang perlu kita lakukan adalah merancang daftar kontrol yang dapat dipilih sehingga kita dapat mengatur ukuran dan jaraknya di CSS. Saya telah memilih satu set tag dengan kotak centang yang tumpang tindih mengenai markup. Tentu saja, desain pastinya sepenuhnya terserah Anda, tetapi Anda dapat menggunakan pola dasar yang telah Anda tulis jika Anda menginginkan titik awal.
.scroll-container {
/* SIZING & LAYOUT */
--itemHeight: 60px;
--itemGap: 10px;
--containerHeight: calc((var(--itemHeight) * 7) + (var(--itemGap) * 6));
width: 400px;
height: var(--containerHeight);
align-items: center;
row-gap: var(--itemGap);
border-radius: 4px;
/* PAINT */
--topBit: calc((var(--containerHeight) - var(--itemHeight))/2);
--footBit: calc((var(--containerHeight) + var(--itemHeight))/2);
background: linear-gradient(
rgb(254 251 240),
rgb(254 251 240) var(--topBit),
rgb(229 50 34 / .5) var(--topBit),
rgb(229 50 34 / .5) var(--footBit),
rgb(254 251 240)
var(--footBit));
box-shadow: 0 0 10px #eee;
}
Beberapa detail tentang topik ini:
--itemHeight
Ini adalah tinggi setiap item dalam daftar.--itemGap
Ini seharusnya menjadi ruang antara dua elemen.- itu
--containerHeight
Variabelnya adalah tinggi .scroll-container. Ini adalah jumlah dari ukuran elemen dan jarak di antara mereka, memastikan bahwa maksimal tujuh elemen ditampilkan pada satu waktu. (Jumlah item yang ganjil memberi kita keseimbangan yang baik karena item yang dipilih berada tepat di tengah vertikal daftar.) - Latar belakang adalah gradien bergaris yang menyorot area tengah, yaitu lokasi item yang dipilih saat ini.
- itu
--topBit
Dan –-footBit
Variabel adalah titik henti warna yang digambar secara visual di area tengah (yang berwarna oranye dalam versi uji coba) untuk mewakili item yang dipilih saat ini.
Saya akan mengatur kontrol dalam kolom vertikal menggunakan flexbox yang dideklarasikan di .scroll-container:
.scroll-container {
display: flex;
flex-direction: column;
/* rest of styles */
}
Setelah pekerjaan tata letak selesai, kita dapat fokus pada bagian penggulirannya. Jika Anda belum pernah bekerja dengan CSS Scroll Snapping sebelumnya, ini adalah cara mudah untuk mengarahkan perilaku scroll container. Misalnya, kita dapat mengetahuinya.scroll-container
Kami ingin mengaktifkan pengguliran ke arah vertikal. Dengan cara ini, dimungkinkan untuk menggulir ke item lainnya yang tidak ditampilkan.
.scroll-container {
overflow-y: scroll;
/* rest of styles */
}
Selanjutnya, kita akan membahasnyascroll-snap-style
Sebuah properti yang dapat digunakan untuk menceritakan.scroll-container
Kami ingin pengguliran berhenti pada suatu elemen — bukan…<>menutup>elemen, tetapi langsung di atasnya.
.scroll-container {
overflow-y: scroll;
scroll-snap-type: y mandatory;
/* rest of styles */
}
Sekarang, item “disematkan” ke suatu item alih-alih membiarkan pengguliran berakhir di mana pun yang diinginkannya. Ada detail kecil lainnya yang ingin saya sertakanoverscroll-behavior
khususnya di sepanjang sumbu y sehubungan dengan demo ini:
.scroll-container {
overflow-y: scroll;
scroll-snap-type: y mandatory;
overscroll-behavior-y: none;
/* rest of styles */
}
overscroll-behavior-y: none
Ini tidak diperlukan untuk membuat ini berfungsi, tetapi ini terjadi ketika seseorang menelusurinya.scroll-container
(sepanjang sumbu y), pengguliran berhenti setelah batas tercapai, dan tindakan pengguliran berkelanjutan lebih lanjut tidak akan memicu pengguliran di wadah pengguliran terdekat. Hanya suatu bentuk CSS defensif.
Saatnya menavigasi ke item di dalam wadah gulir. Namun sebelum kita membahasnya, berikut adalah beberapa gaya dasar untuk elemen itu sendiri yang dapat Anda gunakan sebagai titik awal:
.scroll-item {
/* SIZING & LAYOUT */
width: 90%;
box-sizing: border-box;
padding-inline: 20px;
border-radius: inherit;
/* PAINT & FONT */
background: linear-gradient(to right, rgb(242 194 66), rgb(235 122 51));
box-shadow: 0 0 4px rgb(235 122 51);
font: 16pt/var(--itemHeight) system-ui;
color: #fff;
input { appearance: none; }
abbr { float: right; } /* The airport code */
}
Seperti yang saya sebutkan sebelumnya,--itemHeight
Variabel ditetapkan sebagai ukuran untuk setiap elemen dan kami mendeklarasikannyaflex
kepemilikan –flex: 0 0 var(--itemHeight)
Margin ditambahkan sebelum dan sesudah elemen pertama dan terakhir, sehingga setiap elemen dapat mencapai bagian tengah wadah dengan menggulir.
ituscroll-snap-align
Properti ada untuk diberikan.scroll-container
Titik jepret untuk item. Misalnya, perataan tengah menempatkan bagian tengah elemen (dalam hal ini pusat vertikal) ke.scroll-container
Tengah (juga pusat vertikal). Karena item dimaksudkan untuk dipilih dengan menggesek sajapointer-events: none
Ditambahkan untuk mencegah pemilihan berdasarkan klik.
Detail desain kecil lainnya adalah menetapkan latar belakang baru untuk suatu elemen saat elemen tersebut ada:checked
negara:
.scroll-item {
/* Same styles as before */
/* If input="radio" is :checked */
&:has(:checked) {
background: rgb(229 50 34);
}
}
<>Tapi tunggu!>Anda mungkin bertanya-tanya elemen apa yang ada di dunia ini:checked
Saat kami menghapusnyapointer-events
Pertanyaan bagus! Kita sudah selesai dengan desainnya, jadi mari beralih ke mencari cara untuk “memilih” item hanya dengan menggeseknya. Dengan kata lain, setiap elemen yang diteruskan ke tampilan yang “menempel” pada pusat vertikal wadah harus berperilaku seperti definisi bentuk kontrol pada umumnya. Ya, kita memerlukan JavaScript untuk itu.
let observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
with(entry) if(isIntersecting) target.children[1].checked = true;
});
}, {
root: document.querySelector(`.scroll-container`), rootMargin: `-51% 0px -49% 0px`
});
document.querySelectorAll(`.scroll-item`).forEach(item => observer.observe(item));
itu IntersectionObserver
Objek digunakan untuk memantau (atau “mengamati”) apakah suatu objek ada (disebut target
) melintasi (atau “memotong”) elemen lain. Elemen lain ini bisa jadi adalah viewport itu sendiri, namun dalam kasus ini, kami mencatatnya.scroll-container
Ketika ada.scroll-item
bersinggungan dengannya. Kami menetapkan batas yang diamati denganrootMargin:"-51% 0px -49% 0px"
.
Fungsi pemanggilan dijalankan ketika ini terjadi, dan kita dapat menggunakannya untuk menerapkan perubahan pada elemen target, yang merupakan elemen yang dipilih saat ini.scroll-item
Dalam kasus kami, kami ingin menentukan.scroll-item
Ini sudah setengah jalan .scroll-container
:target.children[1].checked = true
.
Ini melengkapi kodenya. Sekarang, saat Anda menelusuri item, item di posisi tengah adalah item yang dipilih. Berikut ini tampilan demo terakhirnya lagi:
Misalkan, alih-alih memilih item, item tersebut diinstal.scroll-container
Pusat Vertikal Titik pemilihan yang perlu kita pantau adalah bagian atas wadah. Jangan khawatir! Yang harus kita lakukan hanyalah memperbaruiscroll-snap-align
Edit nilai properti center to start di CSS dan hapus:first-of-type
Margin atas '. Dari sana, tinggal memperbarui gradien latar belakang wadah gulir sehingga warnanya berhenti menyorot bagian atas, bukan bagian tengah. seperti ini:
Jika sebuah elemen perlu dipilih terlebih dahulu saat halaman dimuat, kita bisa mendapatkan posisinya di JavaScript (getBoundingClientRect()
) dan digunakanscrollTo()
Cara untuk menggulir wadah ke posisi elemen yang dipilih pada titik pemilihan (yang akan kami katakan sebagai pusat sesuai dengan demo aslinya). Kami akan menambahkan.selecte
Kelas D tentang itu.scroll-item
.
<section class="scroll-container">
<!-- more items -->
<label class="scroll-items selected">
2024
<input type=radio name=items />
</label>
<!-- more items -->
</section>
Ayo pilih.selected
Kategori, mendapatkan dimensinya, dan secara otomatis menggulir ke sana saat halaman dimuat:
let selected_item = (document.querySelector(".selected")).getBoundingClientRect();
let scroll_container = document.querySelector(".scroll-container");
scroll_container.scrollTo(0, selected_item.top - scroll_container.offsetHeight - selected_item.height);
Agak sulit untuk mendemonstrasikannya dalam penyematan CodePen pada umumnya, jadi inilah demo langsung di halaman GitHub (kode sumber). Saya akan menyertakan video juga:
Itu saja! Anda dapat membuat kontrol ini atau menggunakannya sebagai titik awal untuk bereksperimen dengan berbagai tata letak, gaya, animasi, dll. Penting agar pengalaman pengguna menjelaskan kepada pengguna bagaimana pemilihan dilakukan dan item mana yang saat ini dipilih. Jika saya melakukan ini di lingkungan produksi, saya ingin memastikan bahwa saya memiliki pengalaman fallback yang baik ketika JavaScript mungkin tidak tersedia dan markup saya berfungsi dengan baik di pembaca layar.
Referensi dan bacaan tambahan
- Beberapa kegunaan fungsional pengamat persimpangan untuk mengetahui kapan suatu elemen terlihat (Priethi Sam)
- Penjelasan cara memonitor pengontrol persimpangan (Travis Allemand)
- Implementasi praktis CSS Scroll Snapping (MaxColor)
- Keadaan pilihan desain saat ini di tahun 2019 (Chris Cowher)
- Panduan Tata Letak CSS Flexbox (Trik CSS)
- Properti fleksibel CSS (Trik CSS)
- Properti CSS Scroll Snap (MDN).
- Gulir ke (MDN)
Cara Membuat Gulir untuk Memilih Kontrol Formulir Awalnya diterbitkan di CSS-Tricks, bagian dari keluarga DigitalOcean. Anda harus mendapatkan buletin.