Di sebuah situs klien yang saya kerjakan, hero-nya pakai layout bertumpuk. Ada tiga layer absolute di container yang sama: paling bawah background hutan, di atasnya gambar mockup phone, lalu paling atas beberapa tag UI yang mengambang. Teksnya sendiri, headline plus bullet, tidak ikut absolute. Dia hidup di normal flow dan saya dorong turun ke bawah phone lewat padding-top yang dihitung manual, supaya duduk pas di kolong frame phone. Di desktop rapi. Di mobile, awalnya juga rapi.
Lalu QA klien lapor: di mobile, teks hero-nya ketiban gambar phone. Headline-nya nabrak frame dan kebaca cuma setengah. Saya buka di lokal dengan viewport 375px, dan benar, phone-nya melorot turun sampai numpuk sama teks. Anehnya ini baru muncul setelah konten hero saya tambah: headline jadi 3 baris dan bullet-nya jadi grid 4 item. Sebelum konten membengkak, semua aman.
Gejalanya
Yang bikin saya sempat salah tuduh: padding-top teks itu jelas ada angkanya, saya hitung sendiri, dan di desktop hasilnya presisi. Jadi refleks pertama saya jelek seperti biasa. Saya kira angka padding-nya kurang gede, lalu saya naikkan sedikit. Overlap-nya berkurang, tapi muncul jarak menganga di viewport lain. Saya utak-atik z-index, saya curiga object-position, saya sempat mikir ini bug 100dvh di Safari mobile. Semua meleset.
Saya berhenti menebak dan mulai mengukur. Saya inspect section hero-nya, dan di situ angkanya bicara: section yang min-height formula-nya menghasilkan 940px ternyata di-render setinggi 1090px. Konten yang membengkak mendorong section tumbuh 150px lewati batas minimalnya. Itu wajar, memang niatnya section boleh tumbuh. Yang tidak wajar: gambar phone-nya ikut geser turun persis sebanding dengan pembengkakan itu.
Akar masalahnya
Ini bagian yang bikin saya diam sejenak. Ketiga layer absolute itu saya bikin melar penuh dengan top-0 bottom-0. Maksudnya biar tiap layer selalu menutupi seluruh tinggi section. Kelihatannya aman. Masalahnya, layer phone dan layer tag jadi ikut tumbuh saat section melewati min-height. Waktu section jadi 1090px, div phone-nya juga jadi 1090px.
Nah, gambar phone itu pakai object-cover object-center. Dan inilah jebakannya: object-cover object-center selalu me-re-center isi gambar di dalam kotak penampungnya. Begitu kotak penampung membesar, titik pusat gambar ikut bergeser turun. Frame phone yang tadinya berhenti di sekitar 60 persen tinggi section sekarang berhenti di 60 persen dari tinggi yang lebih besar.
Sementara itu padding-top teks saya hitung dari formula tinggi yang TETAP, bukan dari tinggi yang sudah membengkak:
/* globals.css, disederhanakan */
.hero-section-min-h { min-height: max(100dvh, calc(64vh + 400px)); } /* boleh tumbuh lewat ini */
.hero-content-pt { padding-top: calc((64vh + 400px) * 0.60 + 30px); }Angka 0.60 itu fraksi posisi bawah phone terhadap section, dan +30px itu jarak nafas di bawah phone. Jadi teks dijadwalkan mulai di 0.60 x 940 + 30 = 594px. Tapi bawah phone yang asli, karena layer-nya melar ke 1090px, jatuh di 0.60 x 1090 = 654px. Dua angka yang harusnya sinkron malah berpisah 60px. Teks mulai di 594, phone berakhir di 654, jadi 60px teratas teks tertimpa frame. Persis yang dilihat QA.
Bug-nya bukan di angka padding, dan bukan di z-index. Bug-nya: satu sisi (phone) diukur dari tinggi yang melar, sisi lain (padding teks) diukur dari tinggi yang tetap. Selama keduanya bisa berbeda, overlap cuma menunggu konten cukup panjang untuk memicunya.
Perbaikannya
Kuncinya adalah menyamakan basis ukuran. Teks memakai tinggi tetap, jadi phone dan tag juga harus terkunci ke tinggi tetap yang sama, bukan ke tinggi section yang melar. Saya buat satu kelas tinggi tetap dan pasang ke layer phone dan tag. Hanya layer background yang tetap boleh melar penuh untuk menutup overflow:
.hero-layer-h { height: max(100dvh, calc(64vh + 400px)); } /* TETAP, tidak ikut melar */Lalu layer-nya saya ubah dari melar penuh jadi terkunci ke kelas itu:
{/* SEBELUM: layer ikut melar bersama section */}
<div className="absolute inset-x-0 top-0 bottom-0">
<img className="h-full w-full object-cover object-center" />
</div>
{/* SESUDAH: layer dikunci ke tinggi tetap */}
<div className="absolute inset-x-0 top-0 hero-layer-h">
<img className="h-full w-full object-cover object-center" />
</div>Sekarang walau section tumbuh ke 1090px, div phone tetap 940px. object-cover tetap me-re-center, tapi di dalam kotak yang tingginya konstan, jadi bawah phone tetap di 564px, aman di atas teks yang mulai di 594px. Bonusnya: karena phone dan tag sama-sama diukur dari tinggi layer yang identik, penempatan tag dalam persen ikut terkunci relatif ke phone, jadi keselarasan tag ke frame tidak bergeser sama sekali.
Satu detail terakhir. Di mobile grid bullet-nya jadi tidak center karena lebarnya penuh. Saya center-kan sebagai satu grup dengan w-fit mx-auto, lalu kembalikan ke rata kiri di desktop:
<ul className="w-fit mx-auto xl:w-auto xl:mx-0">Setelah itu saya verifikasi di 375, 834, 1024, dan 1440. Overlap hilang di semua breakpoint dan desktop tetap rata kiri seperti semula.
Checklist
- Kalau layer
absolutemelar dengantop-0 bottom-0DAN isinyaobject-cover, ingat gambar akan re-center tiap kali kotaknya membesar. - Overlap muncul saat satu elemen diukur dari tinggi yang melar, elemen lain dari tinggi yang tetap. Samakan basisnya.
- Kunci layer gambar ke
heighttetap, biarkan hanya layer background yang melar untuk menutup overflow. - Hitung
padding-topteks dari formula tinggi yang sama persis dengan yang mengunci layer gambar, jangan dari section yang boleh tumbuh. - Kalau tag diposisikan dalam persen relatif ke phone, mengunci keduanya ke tinggi yang sama otomatis menjaga keselarasannya.
- Uji di beberapa breakpoint dengan konten paling panjang, bukan konten pendek. Overlap ini cuma muncul saat section dipaksa tumbuh lewati
min-height.
