Reveal tukar-kata yang digerakkan scroll bertumpu pada satu asumsi yang jarang ditulis di mana pun: kotak penampungnya setinggi teks yang dia tampung. Kata yang aktif duduk di dalam kotak, kata sebelahnya menunggu di luar, dan progres scroll yang menggeser keduanya. Selama tinggi kotak dan tinggi teks itu angka yang sama, ilusinya utuh. Kalau meleset beberapa piksel, yang muncul bukan kerusakan besar, cuma garis tipis yang kelihatan di sebagian posisi saja.
Saya kena versinya waktu mengerjakan port sistem desain yang targetnya kecocokan visual dan struktural 1:1 dengan referensinya. Di intro homepage ada blok kata yang berotasi, digerakkan scrub scroll, dan kata sebelumnya atau berikutnya terus menembus sebagai strip hantu di posisi pertengahan scrub.
Yang terus menangkap strip itu adalah orang di sisi klien, di desktop maupun di mobile. Bentuk laporannya pendek, dua frasa yang itu-itu saja: "belum sama", "masih beda". Catatan kerja saya untuk projek ini kebetulan sudah punya aturan khusus buat kalimat semacam itu, yaitu begitu frasa itu keluar, muat kedua situs berdampingan lalu ukur selisihnya lewat DOM probe, bukan lewat pengamatan screenshot.
Mengukur, bukan mengamati
Aturannya konkret. Buka situs yang sedang dikerjakan dan referensinya di Playwright pada viewport yang sama, lalu bandingkan computed style dan rect-nya, bukan menatap tangkapan layar dan menebak. Aturan sejenis berlaku untuk sumber vendor: baca dalam-dalam, jangan berasumsi dari screenshot.
Probe-nya sesederhana ini:
const wrap = document.querySelector(".swap_word");
const p = wrap.querySelector("p");
console.log(wrap.getBoundingClientRect().height); // 84
console.log(p.getBoundingClientRect().height); // 74.4Dua angka yang seharusnya sama ternyata tidak sama. Induknya 84px, sementara <p> yang benar-benar terlihat cuma 74.4px. Selisihnya 84 - 74.4 = 9.6px, dan catatan yang saya tulis saat itu membulatkannya jadi "strip slack 10px". Dibandingkan tinggi teksnya sendiri, 9.6 / 74.4 = 0.129, jadi kotaknya 12.9% lebih tinggi daripada isinya.
Kenapa stripnya menembus di posisi tengah
Mekanismenya langsung terbaca begitu dua angka itu berdampingan. Scrub JS menggeser kata sejauh tinggi teks, bukan sejauh tinggi kotaknya:
const textHeight = p.getBoundingClientRect().height; // 74.4
hidden.style.transform = `translateY(-${textHeight}px)`;Kalau kotaknya 84px dan geserannya cuma 74.4px, ada sisa 9.6px yang tidak pernah ikut keluar dari area yang terlihat. Yang mengisi sisa itu adalah kata sebelahnya, dan di posisi pertengahan progres scrub itulah dia menembus ke layar sebagai hantu.
Bagian yang bikin lama, tidak ada yang perlu diperbaiki di JavaScript-nya. Angka geseran itu sudah benar terhadap teks, dan seluruh perbaikan yang akhirnya dipakai memang tidak menyentuh scrub-nya sama sekali. Yang keliru adalah kotak yang menampung teksnya.
Perbaikannya
Yang diperbaiki tinggi kotaknya, supaya sama persis dengan line box teksnya. Tiga hal sekaligus: line-height: 1 pada <p> di dalam, margin nol pada <p> yang sama, lalu wrapper blok untuk kata terlihat dan kata tersembunyi dibuat mengikuti tinggi kontennya persis.
.swap_word__visible p,
.swap_word__hidden p {
line-height: 1;
margin: 0;
}Sesudah itu induknya jadi tepat 74.4px, sama dengan tinggi teksnya. Dan begitu dua angka itu sama, translateY(-74.4px) milik kata tersembunyi menempel rapat ke tepi atas induk. Nol celah, dan nol celah berarti tidak ada kebocoran di state scrub mana pun, bukan cuma di posisi tengah yang tadi kelihatan.
Dua penyumbang 9.6px itu sebetulnya tersebut sendiri di daftar perbaikannya, yaitu leading dari line-height dan margin bawaan <p>. Keduanya dinolkan bersama, dan tinggi induknya turun persis ke tinggi teks.
Invarian yang saya catat
Satu kalimat, dan ini yang saya simpan buat lain kali: waktu membuat reveal tukar-kata pakai translateY, tinggi kontainer harus persis sama dengan tinggi line box. Bukan kira-kira, bukan cukup dekat. Turunannya cuma tiga baris, line-height: 1 dan margin: 0 di <p> bagian dalam, plus wrapper yang mengikuti tinggi kontennya.
Perbaikannya masuk sebagai satu entri changelog di versi 2.9.4 tema itu, isinya persis penghapusan duplikat hantu di blok kata tadi. Waktu catatan status projeknya ditulis, 11 Juni 2026, temanya sudah berjalan di versi 2.10.1, dan seluruh perbaikan visual dan struktural seri 2.9.x masih dipertahankan di sana. Status visual yang dicatat di titik yang sama menyebut Home di lebar 768 dan 393 sudah bersih, tidak ada lagi teks hantu di kata intronya.
Sejak itu, tiap kali saya membuat reveal yang menggeser teks sejauh tinggi teksnya sendiri, hal pertama yang saya ukur bukan animasinya, melainkan apakah dua tinggi itu benar-benar satu angka yang sama.