Skip to content

Teknik Full-Bleed Grid Kartu Tanpa Scrollbar Horizontal

Adityo Guni Waluyo

Satu daftar kartu, dua baris: baris kedua keluar container pakai w-screen dan margin calc, tanpa memicu scrollbar horizontal.

Ringkasan

Pasang w-screen buat full bleed tuh sering muncul scrollbar horizontal, soalnya 100vw dihitung sebelum scrollbar, jadi kelebihan beberapa piksel. Solusinya pakai ml-[calc(50%-50vw)] plus overflow-hidden di section pembungkusnya, bukan di body biar sticky header nggak mati; overflow: clip lebih aman lagi. Markup kartu cukup sekali lewat renderCard IIFE, slicing doang per barisnya.

Saya lagi ngecek tampilan halaman depan di file about-teaser.tsx. Desainnya punya permintaan spesifik: baris pertama kartu perusahaan harus tetap di tengah dengan container standar, tapi baris kedua harus nempel penuh dari ujung kiri ke kanan layar. Saya langsung ketik w-screen di class baris kedua, pikir masalah udah beres.

Pas saya refresh browser, malah muncul scrollbar horizontal di bagian bawah. Layoutnya jadi geser dikit ke kanan. Padahal container di atasnya udah rapi dan nggak ada yang aneh.

Awalnya saya kira ini cuma masalah margin default browser yang belum di-reset. Saya coba nol-kan margin, tapi scrollbarnya masih ada. Saya bahkan sempat menduga ada elemen lain yang leak ke luar container.

Ternyata, w-screen atau 100vw itu menjebak. Spesifikasinya jelas menyebutkan bahwa unit vw dihitung berdasarkan 1% dari lebar initial containing block, dan asumsinya scrollbar itu nggak ada [1]. Di desktop browser dengan scrollbar klasik, elemen selebar 100vw jadi lebih lebar daripada area dokumen yang terlihat, makanya memicu overflow horizontal [3]. Inilah alasan kenapa menerapkan teknik full bleed grid kartu sering gagal kalau cuma modal lebar penuh aja.

Jebakan Lebar Layar Penuh

Masalahnya bukan di niatnya, tapi di eksekusi CSS-nya. Asumsi bahwa w-screen aja sudah cukup itu yang bikin layout rusak. Elemen itu memang selebar viewport, tapi viewport di sini dihitung sebelum scrollbar diperhitungkan. Hasilnya, elemen kita kelebihan beberapa piksel (sekitar 12px di mesin saya, walau angkanya bisa beda tergantung OS dan browser) [3].

Kalo kita biarkan, browser akan menganggap ini sebagai konten yang valid dan memunculkan scrollbar horizontal. Ini jelas mengganggu banget pengalaman pengguna, apalagi cuma gara-gara satu baris kartu.

Rumus Margin dan Clipping yang Tepat

Solusinya adalah menggeser elemen itu ke kiri persis sejauh kelebihan scrollbar, lalu memotong bagian yang overflow.

Pertama, saya pakai kombinasi class w-screen max-w-[100vw] ml-[calc(50%-50vw)] px-md. Margin kiri calc(50% - 50vw) ini yang bikin elemen bergeser dari tengah container menuju tepi kiri layar yang sebenarnya. Pola begini dikenal sebagai full-bleed, istilah pinjaman dari dunia percetakan: konten dicetak sampai ke tepi kertas [4]. Dan justru ini bentuk negative margin yang disiplin. Catatan kecil: px-md di baris kedua menjaga kartu tidak menempel ke tepi fisik layar; width-nya yang penuh, isinya tetap bernapas.

Kedua, dan ini bagian yang paling menentukan, saya harus menambahkan overflow-hidden di elemen <section> pembungkusnya. Jangan pernah pasang ini di body atau html. Kalo kita pasang di level paling atas, kita malah bakal memotong konten lain yang emang butuh scroll vertikal. Dengan menskopnya hanya ke section itu, kita aman memotong kelebihan piksel tanpa merusak layout global.

Ada satu jebakan lagi yang jarang dibahas. overflow-hidden bikin elemen jadi scroll container, dan scroll container itu bisa "dicuri" [10]. Elemen position: sticky selalu nempel ke ancestor terdekat yang punya scrolling mechanism, dan overflow: hidden termasuk yang bikin mechanism itu, meskipun ancestor tersebut nggak pernah di-scroll [11]. Pasang overflow-hidden di body atau pembungkus tinggi, dan header sticky di tempat lain mendadak mati tanpa error apa pun. Kalau cuma butuh memotong tanpa efek samping itu, overflow: clip memotong tanpa menjadikan elemen scroll container, dan tanpa bikin formatting context baru [10].

Unit panjang relatif ini skalanya konsisten karena child element mewarisi computed values dari parent-nya, jadi perhitungannya tetap akurat di berbagai ukuran layar [2]. Class bg-card di section ini juga bukan cuma kosmetik. Saat kita pakai clipping, background section harus konsisten dengan tema kartu supaya transisinya mulus dan nggak menampilkan konten di belakangnya yang terpotong.

Menjaga Kode Tetap Bersih dengan IIFE

Di frontend/src/components/home/about-teaser.tsx, saya punya satu array data bernama groupCompanies. Tantangan berikutnya adalah membagi data ini jadi dua baris tanpa nulis ulang markup kartu dua kali.

Saya pakai fungsi renderCard sebagai IIFE (Immediately Invoked Function Expression). Ini bikin saya bisa mendefinisikan cara render satu kartu di satu tempat, lalu memanggilnya berulang kali dengan data yang beda. Dengan mendefinisikannya di dalam scope komponen, kita menghindari polusi namespace global.

Baris pertama pakai slice groupCompanies.slice(0, 3) dengan grid sm:grid-cols-2 lg:grid-cols-3 di dalam container max-w biasa. Ini menjaga tiga kartu pertama tetap rapi di tengah.

Baris kedua pakai groupCompanies.slice(3) dengan grid lg:grid-cols-4. Section pembungkus baris kedua ini yang dapat class overflow-hidden bg-card, dan grid-nya dapat class breakout w-screen max-w-[100vw] ml-[calc(50%-50vw)] px-md.

Dengan pendekatan ini, teknik full bleed grid kartu jadi rapi tanpa mengorbankan aksesibilitas scroll atau bikin kode jadi berantakan. Saya jadi nggak perlu bikin komponen terpisah cuma buat satu baris yang beda layout. Kalo nanti ada perubahan desain pada satu kartu, misalnya nambahin shadow atau ngubah padding, kita cuma perlu ngubah di satu tempat.

Pola ini bisa dipakai kapan saja kita butuh elemen yang keluar dari container utama tapi tetap ingin menjaga halaman bebas dari scrollbar horizontal yang nggak sengaja. Kuncinya selalu di kombinasi margin kalkulasi dan clipping yang diskop dengan benar.

Sumber

Artikel terkait