D
P
0

HTML & CSS

`overflow-y: auto` di `body` Bikin Semua `position: sticky` Mati? Body Jadi Scroll Container

7 Juli 2026·4 menit baca
`overflow-y: auto` di `body` Bikin Semua `position: sticky` Mati? Body Jadi Scroll Container

Saya lagi mem-port sebuah situs scrollytelling klien ke stack baru. Halaman itu punya beberapa section panjang yang seharusnya "menempel": kamu scroll masuk, panggung di dalamnya diam di layar sementara kamu terus scroll melewati runway yang tinggi, lalu section berikutnya menggantikan. Efek klasik pin-and-scroll. Di build lama semuanya jalan. Di build baru, setelah saya rakit ulang CSS-nya, section-section itu tampil blank.

Bukan blank total dalam arti hilang. Kontennya ada di DOM, tapi tidak ada satu pun yang menempel. Setiap panggung yang harusnya diam malah ikut scroll keluar dari layar lebih awal, meninggalkan runway kosong yang panjang. Jadi kamu scroll, panggung lewat begitu saja, lalu kamu berhadapan dengan ruang kosong sampai section berikutnya masuk. Gap kosong di mana-mana. Dari luar kelihatan seperti section-nya rusak, padahal markup dan tinggi runway-nya persis sama seperti versi lama.

Gejalanya

Yang bikin saya pusing di awal: position: sticky di elemen panggungnya jelas-jelas ada. Saya inspect .section__inner, dan di situ tertulis position: sticky; top: 0. Tidak di-override, tidak ada typo, computed value-nya juga sticky. Tapi elemennya berperilaku seakan-akan position: static. Tidak menempel sedikit pun.

Refleks pertama saya jelek, seperti biasa. Saya kira ada ancestor yang punya overflow: hidden yang memotong konteks sticky-nya, karena itu penyebab sticky mati yang paling sering saya temui. Saya telusuri ke atas dari .section__inner, cek setiap pembungkus satu per satu. Tidak ada overflow: hidden di jalur itu. Saya cek juga apakah ada ancestor yang punya transform atau height yang aneh, yang kadang bikin containing block sticky-nya berubah. Bersih juga.

Yang aneh: ini bukan satu section yang rusak. Semua section pinned di halaman itu mati berbarengan. Ketika sebuah bug menyerang semua instance sekaligus, biasanya penyebabnya bukan di masing-masing komponen, tapi di sesuatu yang global. Itu yang akhirnya mengarahkan saya ke reset CSS-nya.

Akar masalahnya

Di reset CSS halaman itu, ada satu baris yang saya bawa dari build lama tanpa pikir panjang:

html, body {
  overflow-y: auto !important;
}

Kelihatannya jinak. Niatnya cuma memastikan halaman bisa di-scroll vertikal. Tapi baris inilah biang keroknya.

Begitu kamu set overflow-y ke nilai apa pun selain visible, elemen itu berubah jadi scroll container. Set overflow-y: auto di body, dan body promosi jadi scroll container-nya sendiri. Masalahnya, position: sticky cuma menempel di dalam scrollport ancestor terdekatnya. Selama body bukan scroll container, scrollport-nya adalah viewport, dan sticky menempel di sana, persis yang kita mau. Tapi begitu body jadi scroll container, dia mengambil alih peran scrollport untuk semua keturunannya.

Dan di sinilah jebakannya. Panggung-panggung saya lebih tinggi, atau setidaknya runway-nya membuat konteks sticky-nya lebih tinggi, dari body sebagai scrollport. Sebuah elemen sticky tidak bisa menempel kalau containing block-nya tidak menyediakan ruang untuk dia bergeser di dalam scrollport-nya. Karena body sekarang scrollport-nya dan konten pinned-nya "melebihi" cara sticky menghitung ruang gesernya, sticky diam-diam menyerah. Tidak ada error, tidak ada warning. Dia cuma berhenti menempel dan berperilaku seperti elemen biasa. Itulah kenapa setiap panggung ikut scroll keluar alih-alih diam.

Jadi bukan overflow: hidden di ancestor yang membunuhnya, seperti tebakan awal saya. Yang membunuhnya adalah overflow-y: auto di body yang mengubah body jadi scrollport, dan sticky yang tidak lagi punya scrollport viewport untuk ditempeli.

Perbaikannya

Solusinya adalah mengembalikan body supaya bukan scroll container lagi, agar viewport kembali jadi scrollport untuk semua elemen sticky. Saya ganti baris reset-nya jadi:

html, body {
  overflow-y: visible !important;
  overflow-x: clip !important;
}

Dengan overflow-y: visible, body berhenti jadi scroll container. Scrollport kembali ke viewport, dan setiap .section__inner { position: sticky; top: 0 } langsung menempel lagi. Semua section pinned pulih sekaligus dalam satu perubahan. Tidak perlu menyentuh satu pun komponen.

Satu detail penting soal overflow-x. Saya tetap butuh menahan overflow horizontal supaya tidak muncul scrollbar horizontal yang mengganggu. Tapi saya sengaja pakai overflow-x: clip, bukan overflow-x: hidden. Alasannya: overflow-x: hidden di satu sumbu diam-diam memaksa sumbu satunya jadi auto, yang artinya body kembali jadi scroll container dan sticky-nya mati lagi. overflow-x: clip memotong overflow horizontal tanpa membuat scroll container baru, jadi konteks sticky-nya aman. Ini bedanya halus tapi menentukan.

Checklist kalau position: sticky tidak menempel

  • Cek overflow di html dan body. Kalau ada overflow-y atau overflow-x bernilai selain visible, kemungkinan besar itu yang mempromosikan elemen jadi scroll container dan mematikan sticky.
  • Kalau bug menyerang semua elemen sticky sekaligus, curigai CSS global atau reset, bukan komponennya.
  • Telusuri semua ancestor untuk overflow: hidden, transform, atau filter; ketiganya bisa memotong atau menggeser konteks sticky.
  • Untuk menahan overflow horizontal tanpa membunuh sticky, pakai overflow-x: clip, bukan overflow-x: hidden.
  • Ingat aturan intinya: sticky cuma menempel di dalam scrollport ancestor terdekatnya, dan set overflow non-visible di sebuah elemen menjadikan elemen itu scrollport.

Sejak itu, kalau ada sticky yang menolak menempel, hal pertama yang saya cek bukan komponennya, tapi overflow di html dan body. Sembilan dari sepuluh kali, jawabannya sudah ada di reset CSS yang saya salin tanpa berpikir.