Memperbaiki Horizontal Scroll dan Navbar Mobile: Studi Kasus Nyata
Mencari elemen penyebab halaman melebar, memperbaiki ukuran intrinsik, merapikan kategori mobile, dan menguji viewport 320–1280 piksel.
Pada tangkapan layar mobile, artikel NgodingSantai melebar melewati viewport dan navbar terlihat terdorong ke kanan. Menu kategori juga membungkus sebagai deretan teks tanpa kelompok yang jelas. Perbaikan dilakukan dari ukuran intrinsik setiap komponen, bukan dengan membuat daftar model ponsel atau sekadar memotong overflow pada body.
- Scrollbar horizontal muncul pada halaman artikel.
- Bagian kiri brand terpotong ketika viewport sudah bergeser.
- Code block atau teks panjang dapat mempertahankan lebar minimum.
- Tujuh kategori mobile tidak memiliki target dan kolom yang stabil.
Buktikan dokumen memang melebar
Scrollbar dapat berasal dari panel DevTools atau zoom browser, jadi ukuran diambil langsung dari dokumen. Kondisi gagal didefinisikan sebagai scrollWidth > innerWidth + 1. Toleransi satu piksel menghindari pembulatan subpixel.
const root = document.documentElement;
console.table({
viewport: innerWidth,
root: root.scrollWidth,
body: document.body.scrollWidth,
overflow: root.scrollWidth > innerWidth + 1
});
Urutkan elemen yang keluar viewport
Setiap elemen dipetakan ke bounding rectangle. Hasilnya difilter untuk sisi kanan melebihi viewport atau sisi kiri negatif. Pemeriksaan dilakukan saat menu tertutup dan terbuka karena popup atau transform dapat mengubah hasil.
[...document.querySelectorAll('body *')]
.map(el => ({ el, r: el.getBoundingClientRect() }))
.filter(({ r }) => r.right > innerWidth + 1 || r.left < -1)
.sort((a, b) => b.r.right - a.r.right);
Pahami minimum size pada grid dan flex
Grid child dan flex child secara default dapat menolak menyusut di bawah min-content. String code, URL, atau tabel lalu memperlebar track. minmax(0,1fr) pada grid dan min-width:0 pada child mengizinkan track menyusut sesuai container.
.article-layout {
display: grid;
grid-template-columns: minmax(0, 760px) minmax(0, 260px);
}
.article-layout > *,
.prose,
.prose > * {
min-width: 0;
max-width: 100%;
}
Berikan scroll lokal untuk code dan tabel
Kode tidak boleh dipatahkan di tengah token hanya demi muat. Elemen pre diberi overflow-x:auto dan maksimum 100 persen. Tabel artikel juga menjadi area scroll lokal ketika kolom tidak mungkin direflow tanpa kehilangan hubungan data.
.prose pre,
.prose table {
display: block;
width: 100%;
max-width: 100%;
overflow-x: auto;
}
Jaga media mempunyai dimensi dan batas
Gambar, video, iframe, dan SVG tidak melebihi container. Atribut width dan height pada gambar memberi rasio sebelum resource selesai dimuat sehingga layout tidak meloncat.
Hitung kebutuhan header 320 piksel
Header berisi brand dan tiga tombol 44 piksel. Brand boleh menyusut dan teks memakai ellipsis pada ruang sangat sempit. Pada 320 piksel, tombol pencarian dapat disembunyikan karena fungsi Cari tetap tersedia di panel mobile. Tombol tema dan menu dipertahankan.
@media (max-width: 320px) {
.header-actions > a.icon-btn { display: none; }
.navbar-shell > .brand { max-width: calc(100% - 94px); }
}
Rapikan kategori sebagai grid kartu
Pada 375–430 piksel, dua kolom masih memberi target cukup lebar. Di bawah 390 piksel, grid berubah menjadi satu kolom. Setiap link mempunyai border, radius, min-height, dan wrapping sendiri; label panjang tidak menimpa item berikutnya.
Body clip hanya pertahanan terakhir
overflow-x:clip dipertahankan untuk mencegah efek transform animasi menghasilkan scrollbar sesaat, tetapi bukan perbaikan utama. Audit tetap gagal jika documentElement.scrollWidth lebih besar dari viewport. Dengan demikian elemen penyebab tidak lolos hanya karena secara visual terpotong.
Gunakan breakpoint saat hubungan elemen rusak
Desktop navigation disembunyikan pada 900 piksel karena ruang link dan actions mulai tertekan, bukan karena 900 mewakili satu jenis tablet. Article layout menjadi satu kolom pada titik sama. Card grid berubah dua lalu satu kolom berdasarkan ruang baca, sedangkan font memakai clamp dengan batas minimum dan maksimum.
Matriks audit otomatis dan manual
| Lebar | Fokus otomatis | Fokus manual |
|---|---|---|
| 320 | Overflow, header actions, satu kolom kategori | Sentuhan dan scroll panel |
| 375 | Artikel dan code block | Pembesaran teks |
| 430 | Card, form, dialog | Orientasi |
| 768 | Peralihan layout | Keyboard dan zoom |
| 1280 | Dropdown dan sidebar | Pointer serta focus path |
Referensi primer
Uji kata terpanjang dan data nyata
Layout yang hanya diuji dengan “HTML” belum membuktikan label “Web Performance” atau judul artikel panjang dapat reflow. Kartu diisi dengan data produksi, URL panjang ditempatkan pada prose, dan snippet shell diuji di dalam pre. overflow-wrap:anywhere dipakai pada prose biasa, bukan pada kode.
Jangan mengecilkan teks untuk menyelamatkan layout
Jika header tidak muat, prioritas kontrol dan struktur diubah; font body tidak dipaksa menjadi sangat kecil. Brand dapat ellipsis dan pencarian tersedia melalui panel. Target sentuh tetap 44 piksel. Keputusan ini menjaga operasi meskipun ruang sempit.
Periksa tinggi viewport juga
Mode landscape atau keyboard virtual mengurangi tinggi. Panel menu memakai 100dvh dan scroll internal sehingga link bawah tetap dapat dicapai. Dialog pencarian mempunyai max-height serta margin viewport. Audit lebar saja dilengkapi pemeriksaan manual pada tinggi pendek.
Reproduksi kecil sebelum mengubah seluruh stylesheet
Gunakan playground Grid dengan minimum 360px, lalu buka pada viewport 320px. Contoh memakai min(100%, 360px), sehingga minimum kartu mengikuti kontainer sempit. Unduh HTML dan ganti minimum itu menjadi 360px tetap untuk membuat perbandingan sendiri.
document.documentElement.scrollWidth > document.documentElement.clientWidthEkspresi ini mendeteksi lebar dokumen, bukan sumber masalahnya. Periksa ukuran kartu, gambar, pre, dan navbar secara terpisah. Scroll di dalam blok kode bisa disengaja; scroll horizontal seluruh halaman biasanya mengganggu pembacaan. Simpan hasil pada checklist audit bersama ukuran viewport dan browser. Percobaan ini adalah reproduksi yang dapat diulang, bukan screenshot kondisi produksi lama.
