Debugging Navbar Mobile dan Dropdown yang Tidak Konsisten
Menelusuri perbedaan markup antarlaman, event pointer, fokus, dan state menu hingga navigasi dibangun konsisten oleh satu script.
Bug navbar NgodingSantai terlihat seperti masalah CSS: tab Kategori berwarna pada halaman Tentang, menu berbeda antarlaman, dan tombol mobile menghasilkan susunan tidak rapi. DevTools menunjukkan akar yang lebih mendasar—setiap file HTML mempunyai header statis yang tidak identik, sedangkan JavaScript menambahkan perilaku dengan asumsi markup selalu sama.
- CSS aktif salah memilih elemen.
- Header tiap halaman mempunyai jumlah kontrol berbeda.
- Listener terpasang pada node lama setelah navigasi dinormalisasi.
- Overflow artikel membuat seluruh viewport bergeser, bukan headernya sendiri.
Reproduksi dengan matriks halaman
Bug tidak diperiksa hanya pada beranda. Daftar reproduksi mencakup Beranda, Artikel, Kategori, Tentang, Kontak, serta satu artikel pada viewport 320, 375, 768, dan 1280 piksel. Catatan menyimpan halaman, ukuran, tema, keadaan menu, dan cara input.
Bandingkan DOM efektif, bukan source satu file
Elements panel memperlihatkan DOM setelah app.js berjalan. Query sederhana menghitung navigasi, tombol kategori, panel mobile, dan link. Jika hasil berbeda antarlaman, bug berasal dari normalisasi atau script gagal sebelum selesai.
({
desktop: document.querySelectorAll('.desktop-nav').length,
category: document.querySelectorAll('.category-toggle').length,
mobile: document.querySelectorAll('[data-mobile-panel]').length,
links: document.querySelectorAll('.mobile-panel a').length
})
Bangun satu state dari pathname
Fungsi normalizeNavigation menghitung section aktif dari filename dan data-root. Header statis lama dilepas, kemudian desktop navigation, action buttons, dan mobile panel dibangun sekali. Pendekatan ini dipilih karena situs belum mempunyai template engine. Jangka panjang, generator layout dapat menggantikan duplikasi HTML sepenuhnya.
Ambil referensi setelah node final tersedia
Listener mobile dipasang setelah normalisasi selesai. Jika script menyimpan referensi tombol sebelum node lama diganti, listener akan bekerja pada elemen yang sudah tidak ada di dokumen. Urutan eksekusi dan scope referensi diperiksa menggunakan breakpoint serta isConnected.
const mobileToggle = document.querySelector('[data-mobile-toggle]');
const mobilePanel = document.querySelector('[data-mobile-panel]');
console.assert(mobileToggle?.isConnected);
console.assert(mobilePanel?.isConnected);
Bedakan state kelas dan state aksesibel
Ketika panel dibuka, tiga hal harus sinkron: kelas open, aria-expanded="true", dan ikon close. Fungsi setMobileOpen menjadi satu pintu perubahan sehingga click, Escape, perpindahan breakpoint, dan klik link tidak menulis state sendiri-sendiri.
Temukan overflow dengan pengukuran
Ketika header tampak bergeser, Console membandingkan documentElement.scrollWidth dan innerWidth. Jika lebih besar, setiap elemen yang melampaui viewport diurutkan berdasarkan getBoundingClientRect().right. Code block, grid child, tabel, atau string panjang sering menjadi penyebab.
[...document.querySelectorAll('body *')]
.map(el => ({ el, rect: el.getBoundingClientRect() }))
.filter(x => x.rect.right > innerWidth + 1 || x.rect.left < -1)
.map(x => [x.el.tagName, x.el.className, x.rect.left, x.rect.right]);
overflow-x:hidden tidak dipakai sebagai satu-satunya perbaikan karena hanya memotong bukti. Child grid diberi min-width:0, track memakai minmax(0,1fr), media dibatasi, dan pre memiliki scroll lokal.
Periksa event pointer dan focus
Event listener breakpoint pada pointerenter mengabaikan pointer touch. Focusin membuka menu dan focusout menjadwalkan penutupan. Timer diperiksa agar pointer dapat melewati gap popup. Click luar menutup tanpa mengganggu click pada link.
Buat audit regresi yang dapat gagal
Script browser audit tidak hanya mengambil screenshot. Ia memeriksa jumlah menu, status aktif, ukuran target, overflow, warna aktif kategori, H1, error console, dan posisi artikel. Hasil berupa JSON dengan daftar kegagalan sehingga perubahan CSS berikutnya tidak hanya dinilai dari satu gambar.
Kesimpulan debugging
- Reproduksi masalah pada lebih dari satu halaman dan viewport.
- Periksa DOM setelah JavaScript, bukan asumsi dari source.
- Satukan perubahan state dalam satu fungsi.
- Ukur overflow dan perbaiki elemen penyebab.
- Tambahkan audit regresi untuk gejala yang pernah terjadi.
Referensi primer
Tambahkan guard tanpa menyembunyikan kegagalan
Optional chaining digunakan pada komponen yang memang opsional per halaman, misalnya tombol kembali ke atas. Komponen inti seperti header tetap mempunyai pemeriksaan awal. Guard tidak boleh membuat script diam ketika markup wajib hilang; audit menghitung komponen dan gagal jika jumlahnya salah.
Waspadai listener yang didaftarkan ulang
Normalisasi berjalan sekali pada DOMContentLoaded. Jika kelak situs memakai navigasi client-side, listener dokumen dan media query perlu dikelola agar tidak berlipat. Untuk sekarang, setiap halaman melakukan load penuh sehingga lifetime listener sama dengan dokumen.
Screenshot membantu, assertion menentukan
Screenshot menunjukkan susunan visual, tetapi sulit membuktikan aria-expanded, jumlah link, error console, atau overflow satu piksel. Audit menyimpan keduanya: gambar untuk review manusia dan JSON assertion untuk kondisi yang dapat dihitung.
Latihan state UI melalui input warna yang salah
Buka pemeriksa kontras, masukkan #xyz, lalu perbaiki menjadi #fff. Pada input salah, hasil harus dinyatakan tidak tersedia dan field ditandai aria-invalid. Sesudah valid, error dibersihkan dan hasil baru muncul. Tujuannya memastikan UI tidak terus menampilkan status lulus dari input sebelumnya.
Periksa console saat menukar warna dan memilih preset. Tidak boleh ada exception yang memutus pembaruan berikutnya. Pada playground, ubah jumlah kartu menjadi dua, lalu sembilan; jumlah anak kontainer harus ikut berubah tanpa duplikasi listener.
Percobaan ini memberi kasus kecil untuk menelusuri input, validasi, state, dan render. Simpan langkah kegagalan di catatan audit sebelum mengubah implementasi.
