width/height Gambar Wajib Eksplisit Biar Layout Stabil di Next.js
Ikon per-kategori fallback tanpa dimensi eksplisit bikin sidebar goyang. width/height di img atau next/image, plus og:image:width/height, jaga CLS aman.
Deploy perubahan fallback ikon per-kategori habis, saya buka sidebar. Kategori yang tadinya cuma teks sekarang punya gambar. Bagus. Tapi pas scroll, daftar itu kayak joget. Gambar muncul satu-satu, masing-masing beda ukuran, dan teks di bawahnya loncat-loncat nyesuaikan.
Dugaan awal saya: masalah CSS. Mungkin ada margin atau padding yang nggak konsisten antar kategori. Tapi nggak. Komponen category item-nya identik satu sama lain. Bedanya cuma di gambar. Kategori dengan ikon asli punya dimensi yang udah fix, sementara kategori yang dapet fallback icon tampil dengan ukuran default dari browser, dan itu bukan angka yang kita set.
Masalahnya gampang kelewat: <img> tanpa width dan height eksplisit bikin browser nggak tahu mau alokasi ruang berapa di layout. Gambar load, dapet dimensi, dan seluruh konten di bawahnya terdorong ke bawah. Itu yang bikin sidebar goyang.
Layout Shift Bukan Cuma Soal Estetika
CLS (Cumulative Layout Shift) itu salah satu Core Web Vital yang diukur Google. Ambang yang dianggap baik bisa mencapai ≤0.1 di percentile ke-75 [3]. Angka kecil, tapi dampaknya kerasa banget buat user, apalagi di sidebar yang panjang, di mana satu gambar yang muncul telat bisa geser seluruh daftar.
Perubahan di commit cluster ini (5dec350 dan tiga commit terkait) pada dasarnya menambahkan fallback ikon untuk kategori yang sebelumnya nggak punya gambar. Niatnya bagus: biar semua kategori punya representasi visual. Tapi efek sampingnya: gambar-gambar fallback itu punya dimensi yang nggak stabil. Ikon asli udah di-export dengan ukuran tetap, fallback icon datang dari path yang beda, dan browser harus fetch dulu sebelum tahu size-nya.
Next.js Image component seharusnya bisa mitigasi ini. <img> native lebih lambat di LCP dan lebih boros bandwidth dibanding next/image [1]. Lint @next/next/no-img-element memang mendorong pakai Image karena dia otomatis handle size optimization dan visual stability [2]. Tapi otomatis itu cuma jalan kalo kita kasih data yang cukup. Width dan height tetap harus di-set eksplisit, bahkan di next/image. Tanpa itu, component-nya tetap nggak bisa mencegah shift.
Gambar yang di-import secara statis bakal otomatis ke-detect intrinsic dimensions-nya [2]. Tapi kalo gambarnya dinamis (datang dari data kategori), kita dari data kategori, path-nya beda-beda, kita harus nyetel manual.
Praktik yang Mencegah Shift
Begitu masalahnya ketemu, fix-nya gampang: set width dan height di setiap gambar ikon kategori, termasuk fallback. Apakah pakai <img> native atau next/image, keduanya butuh dimensi eksplisit supaya browser bisa reserve space sebelum gambar load.
Kalo pakai next/image, tentukan juga sizes attribute supaya loader-nya nggak download gambar lebih gede dari yang dibutuhkan. Di sidebar, gambar kemungkinan cuma tampil sekitar 24-32px, jadi sizes="32px" udah cukup, browser nggak perlu fetch versi 256px.
Satu hal yang saya pelajari: <img> native itu masih oke dipakai di konteks tertentu, termasuk di blog post atau prose panjang, selama dimensinya di-set. Iklim lint sekarang memang condong ke next/image [1], dan untuk halaman product atau landing page saya setuju. Tapi buat konten editorial atau situasi di mana kamu butuh gambar tanpa optimasi build-time Next.js, <img> dengan width/height tetap aman dari sisi CLS.
Sisi lain yang sering kelewat: og:image. Setiap halaman yang punya Open Graph image sebaiknya juga set og:image:width, og:image:height, dan og:image:alt [4]. Tanpa dimensi ini, platform yang nge-fetch preview kayak Twitter, Facebook, atau WhatsApp juga bisa nge-shift layout di card mereka. Alt text recommended, tapi jarang dipakai secara konsisten. Beberapa commit di cluster ini juga nambahin dimensi og:image, dan itu langkah yang benar.
Rumusnya cuma satu: selalu set dimensi gambar secara eksplisit. Tiga angka yang wajib ada:
widthdanheightdi<img>atau<Image>— browser pakai ini buat hitung aspect ratio dan alokasi space [2] [3].og:image:widthdanog:image:heightdi<head>— parser Open Graph pakai ini buat render preview tanpa shift [4].- CLS score ≤0.1 — target yang harus dipertahankan, terutama di halaman dengan banyak gambar dinamis seperti sidebar kategori [3].
Saya sendiri sempat kejebak godaan ini: "udah pakai next/image, harusnya aman kan?" Nggak juga. next/image kerja bagus kalo datanya lengkap. Tanpa width/height eksplisit, dia tetap terjebak di masalah yang sama. Tooling modern udah bagus, tapi tetap butuh input yang benar dari kita.
Sumber
- [1] Next.js Docs: lint no-img-element: pakai next/image karena lebih cepat dan stabil
- [2] Next.js Docs: Image Optimization: intrinsic width/height, size optimization, visual stability
- [3] web.dev: Cumulative Layout Shift (CLS), threshold ≤0.1 di percentile ke-75
- [4] Open Graph Protocol: og:image:width, og:image:height, og:image:alt