Galeri foto yang berhenti pas di tengah kartu dan carousel yang kembali ke posisi rapi setelah dilepas — selama bertahun-tahun pola semacam itu ditulis dengan JavaScript: mendengarkan event scroll, menghitung jarak terdekat, lalu menganimasikan posisi gulir. CSS menyediakan mekanisme bawaan untuk kebutuhan yang sama melalui scroll snap : kita menyatakan titik-titik penahanan (snap point) di CSS, dan browser menahannya setiap kali gulir berhenti. Fitur ini didukung penuh di seluruh browser utama dan telah lama menjadi bagian dari Baseline. Chapter ini membahas dua sisi kontraknya — container yang menentukan sumbu dan kekakuannya, item yang menentukan posisi penahannya — lalu membangun galeri horizontal sederhana.
Container: scroll-snap-type #
Properti scroll-snap-type
ditulis pada elemen yang digulir — container dengan overflow selain visible. Nilainya terdiri dari dua bagian: sumbu (x, y, atau both) dan tingkat kekakuan (mandatory atau proximity):
.galeri {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
gap: 12px;
}Mari kita telaah kedua bagian nilainya:
x: penahanan bekerja pada sumbu horizontal — cocok untuk galeri yang digulir ke samping. Untuk daftar vertikal gunakany, danbothbila dua sumbu sama-sama ditahan.mandatory: setiap kali gulir berhenti, browser wajib menempelkan posisi ke snap point terdekat. Pengguna tidak dapat berhenti di posisi di antara dua titik — cocok untuk kartu lebar penuh, tetapi terasa kaku bila konten beragam ukuran.proximitysebagai alternatif: browser menahan hanya bila posisi gulir berhenti dekat dengan sebuah snap point; di antara titik, gulir bebas. Nilai ini lebih lembut untuk konten campuran.
Item: scroll-snap-align #
Container hanya menyatakan “akan menahan”; item yang menyatakan “di mana”. Properti scroll-snap-align
ditulis pada setiap anak, dengan tiga kata kunci: start menyelaraskan tepi awal item ke tepi awal container, center memusatkan item, dan end menyelaraskan tepi akhirnya. Demo chapter ini memakai center pada semua petak dan start pada satu petak pembanding:
.galeri .petak {
flex: 0 0 220px;
height: 120px;
scroll-snap-align: center;
}
.galeri .petak-tepi {
scroll-snap-align: start;
}Dua penyesuaian halus melengkapi pola galeri. Pertama, flex: 0 0 220px menjaga petak tidak menyusut — snap point pada item yang menyusut akan bergeser-rempet dan penahanan menjadi tidak nyaman. Kedua, jarak antara snap point dan tepi container dapat disetel lewat scroll-padding pada container atau scroll-margin pada item; misalnya scroll-padding-inline: 16px menggeser semua titik penahanan 16px masuk dari tepi, sejajar dengan padding galeri.
Satu properti lagi patut dikenal sejak awal: scroll-snap-stop pada item. Nilai default normal membiarkan gulir cepat melompati beberapa snap point sekaligus, sedangkan always memaksa gulir berhenti di setiap titik — berguna untuk deretan kartu yang masing-masing wajib dibaca, dan sebaiknya tidak dipakai pada deretan panjang karena menghambat perpindahan cepat.
Demo: Galeri Horizontal #
<div class="galeri" data-expected='{"scroll-snap-type":"x mandatory","overflow-x":"auto"}'>
<div class="petak" data-expected='{"scroll-snap-align":"center"}'>Satu</div>
<div class="petak">Dua</div>
<div class="petak petak-tepi" data-expected='{"scroll-snap-align":"start"}'>Tiga</div>
<div class="petak" data-expected='{"scroll-snap-align":"center"}'>Empat</div>
</div>Hasil di Browser:
Galeri dapat digulir horizontal dengan garis gulir samar — computed
overflow-x: auto dan scroll-snap-type: x mandatory pada container.
Setiap petak membawa scroll-snap-align: center sehingga saat gulir
berhenti, petak terdekat dipusatkan pada galeri; petak "Tiga"
dengan class petak-tepi tercatat "start" — melekat ke tepi awal.Nilai computed pada demo tersebut diperiksa otomatis oleh harness melalui atribut data-expected. Uji perilaku penahannya secara manual: seret atau gulir galeri lalu lepaskan — posisi gulir menempel ke petak terdekat, bukan berhenti di posisi sembarang.