Skip to content

Sidebar Sticky Diam-Diam Gagal di Dashboard Saya

Adityo Guni Waluyo

Sidebar sticky yang gagal tanpa satu baris error: stretch flexbox makan ruang scroll, offset top ketutup header, dan ancestor ber-overflow.

Ringkasan

Sticky sidebar gue nggak jalan gara-gara tiga hal: flexbox stretch bikin parent sedinggi viewport, top-0 nyangkut di balik header fixed, dan ada ancestor overflow-hidden yang motong. Fix-nya cuma items-start plus offset 55px yang disesuaikan tinggi header. Sekarang tiap pasang sticky, gue selalu cek inset, ruang scroll parent, dan rantai ancestor-nya.

Sore itu saya buka dashboard fleet, scroll dikit buat liat server paling bawah, terus langsung curiga. Sidebar riwayat alert yang baru saya pasang di kanan layar harusnya nempel terus selama halaman digulir. Faktanya, dia ikut naik ke atas bareng konten. Nggak ada error di konsol, nggak ada warning, nggak ada apa-apa. Cuma sebuah position: sticky yang nggak jalan, dan layar terlihat normal-normal saja.

Layout-nya waktu itu sederhana: satu flex row berisi kolom utama di kiri dan aside di kanan. Versi pertama saya tulis dengan class Tailwind kayak gini di aside-nya:

<aside class="w-full lg:w-[30%] lg:min-w-[280px] lg:max-w-[380px]
  shrink-0 lg:sticky lg:top-0 lg:max-h-screen lg:overflow-y-auto">
  ... alerts ...
</aside>

Di mata saya waktu itu udah lengkap. Sticky, ada offset, ada batas tinggi, ada scroll di bagian dalam. Tiga commit berikutnya saya habiskan buat nebak-nebak: geser offset, ganti tinggi, tambah border. Semua nggak nyampe ke akar masalah, karena masalahnya bukan di angka. Ada tiga prasyarat sticky yang saya lewatkan semua, dan ketiganya gagal dalam diam [1].

Stretch-nya flexbox makan ruang scroll

Prasyarat pertama: elemen sticky cuma "nempel" di dalam rentang parent-nya. Kalau parent-nya udah sama tingginya dengan viewport, nggak ada jarak scroll yang tersisa, jadi perilaku sticky nggak pernah punya momen buat aktif. Nah, di sinilah flexbox jualan palu. Nilai awal align-items di flex container itu stretch, jadi semua item flex ditarik setinggi item tertinggi [2]. Kolom utama saya panjangnya ratusan piksel ke bawah, dan aside ikut memanjang penuh mengikuti. Parent aside jadi setinggi halaman, sejajar viewport di titik awal, dan sticky-nya mendem.

Perbaikannya satu kata: items-start di flex row-nya. Tinggi aside balik mengikuti kontennya sendiri, dan sekarang ada ruang scroll buat dia jalan-jalan di dalamnya. Ini yang bikin saya kesal sekaligus kagum: satu properti default yang jarang dipikirkan, dampaknya bikin lima class sticky saya jadi hiasan.

Inset wajib non-auto, dan header fixed bikin rumit

Prasyarat kedua soal offset. Dokumentasi MDN bilang langsung: kalau properti inset di satu axis nilainya auto semua, sticky di axis itu berperilaku seperti relative [1]. Saya udah pasang lg:top-0 sih, jadi prasyarat ini formalitas? Belum, karena header dashboard saya fixed. top-0 naruh sidebar tepat di bawah mulut viewport, persis di belakang header. Ini bagian yang saya tangani paling nggak elegan: commit pertama setel offset 48 piksel, commit kedua 50, commit ketiga 55 plus border 1px biar pisah rapi dari header. Tiga commit buat cari angka yang pas, karena nilainya emang tergantung tinggi header dashboard saya sendiri, nggak ada angka universal yang bisa saya salin dari mana pun.

Ancestor overflow yang "menelan" sticky

Prasyarat ketiga paling licik: elemen sticky nempel ke ancestor terdekat yang punya mekanisme scrolling, dan ancestor ber-overflow hidden, scroll, atau auto ikut dihitung, meskipun dia bukan yang beneran scroll [1]. Satu utility overflow-hidden yang dipasang buat ngebulatkan sudut kartu, dan sticky-nya langsung dijemput malaikat di dalam wrapper itu, nggak sampai viewport. Saya jadi kebiasaan ngesek rantai ancestor dari aside ke atas, pastikan nggak ada yang motong overflow sebelum sampai akar halaman.

Dua mekanik di atas sekarang udah dibungkus rapi di dokumentasi resmi. Halaman Tailwind sendiri mendeskripsikan sticky persis kayak yang saya alami: relative sampai melewati ambang tertentu, lalu fixed sampai parent-nya keluar layar [3]. Desainnya bagus. Yang bikin naik darah adalah cara gagalnya: senyap, tanpa satu baris error pun.

Kapas 400px yang jadi sampah

Ada sisa lain dari kekacauan awal itu. Di versi pertama, saya gendong daftar alert di dalam wadah ber-max-h-[400px] plus scroll internal, takut list-nya kepanjangan. Setelah stretch dibenerin dan lg:max-h-screen beneran kerja di aside, batas 400px itu jadi redundan. Tinggi sidebar udah dicapped sama tinggi viewport, dan scroll listnya pindah ke level yang bener. Saya cabut. Kode yang tumbuh dari tebakan emang suka ninggalin gear yang udah nggak dipakai.

Sekarang sticky masuk daftar properti yang nggak boleh saya pasang sambil lalu. Tiga prasyaratnya saya cek berurutan: inset harus non-auto, parent harus punya ruang scroll, dan nggak boleh ada ancestor ber-overflow di jalur ke viewport. Kalau salah satu nggak terpenuhi, saya tahu persis mana yang harus dibuka duluan. Dan ke depannya, layout dua kolom plus sticky ini jadi pola bawaan buat semua halaman panel saya, lengkap dengan offset yang nempel di tinggi header, bukan angka tempelan hasil nebak.

Sources

  1. MDN Web Docs: position
  2. MDN Web Docs: Aligning items in a flex container
  3. Tailwind CSS: position

Artikel terkait