D
P
0
← Semua artikel Read in English

Shopify, Liquid & Theme CLI

Logo Gepeng Padahal Sudah `width: auto`? Reset `img { max-width: 100% }` Mengunci Lebar ke Parent

· · 4 menit baca
Logo Gepeng Padahal Sudah `width: auto`? Reset `img { max-width: 100% }` Mengunci Lebar ke Parent

Gejalanya

Saya sedang memindahkan desain header dan footer sebuah toko ke tema baru. Logonya berupa file gambar persegi, dan yang perlu tampil cuma bagian wordmark-nya saja. Trik yang saya pakai standar: bikin wrapper kecil 200×36 dengan overflow: hidden, lalu gambarnya saya besarkan sampai height: 280px dengan width: auto, sehingga wrapper itu berfungsi sebagai jendela yang memotong sisa artwork-nya.

Begitu dipasang, hasilnya salah dengan cara yang bikin gatal. Tinggi potongannya pas, posisinya pas, tapi tulisan di logonya gepeng. Huruf-hurufnya terlihat seperti ditarik menyempit ke arah horizontal, mirip teks yang dipaksa masuk ke kolom yang terlalu sempit. Dan bukan cuma di header, footer kena persis sama.

Refleks pertama saya menyalahkan diri sendiri: pasti angka height-nya salah, atau ada transform sisa dari tema lama yang men-scale gambarnya tidak seragam. Saya cek dua-duanya, bersih. width juga sudah jelas auto, jadi secara teori browser mestinya menghitung lebarnya sendiri dari rasio asli gambarnya.

Angka yang membongkar semuanya

Yang akhirnya menyelesaikan tebak-tebakan bukan membaca CSS lagi, tapi mengukur elemennya. Saya hover gambarnya di DevTools dan lihat kotak dimensinya:

diharapkan : 280 × 280
kenyataan  : 200 × 280

Gambarnya persegi, tingginya 280, jadi lebarnya seharusnya ikut 280. Yang muncul malah 200, angka yang tidak saya tulis di mana pun untuk gambar ini. Tapi 200 itu terasa familiar, karena itu persis lebar wrapper-nya.

Dari situ saya pindah ke tab Computed, cari properti max-width, dan di sanalah pelakunya duduk manis:

max-width: 100%

Bukan dari rule saya. Nilainya datang dari base reset tema.

Akar masalahnya

Reset-nya baris klasik yang ada di hampir semua tema modern:

img,
picture,
video,
canvas,
svg {
  max-width: 100%;
}

Kelihatannya tidak berbahaya, dan memang biasanya begitu. Tapi urutan hitungan browser bikin baris ini punya efek samping yang tidak kelihatan.

Waktu height diisi eksplisit dan width-nya auto, browser pertama-tama menurunkan lebar dari rasio asli gambar. Untuk file persegi setinggi 280px, lebarnya jadi 280px. Baru setelah itu tahap clamping min/max jalan: lebar hasil hitungan tadi ternyata melebihi max-width, yang nilainya 100% dari parent alias 200px, jadi lebarnya dipotong ke 200px.

Yang tidak terjadi adalah penyesuaian balik. Tingginya tetap 280px karena saya menuliskannya eksplisit, bukan auto, jadi tidak ada yang menurunkannya ulang dari rasio. Hasil akhirnya 200×280 di file yang aslinya persegi, dan gambarnya di-render dengan rasio yang salah. Gepengnya bukan ilusi, browser memang benar-benar memampatkannya.

Ini juga menjelaskan kenapa reset itu aman di 99% kasus lain. Pola normalnya adalah lebar mengikuti kontainer dan height: auto. Kalau lebarnya kena clamp, tingginya ikut dihitung ulang secara proporsional, jadi rasionya selalu terjaga. Reset ini baru menggigit persis di kasus sebaliknya: satu dimensi dipatok manual, dimensi satunya auto, dan hasil hitungan auto itu lebih besar dari parent-nya.

Perlu dicatat juga bahwa ini kelas gepeng yang berbeda dari dua tetangganya yang sering tertukar. Bukan elemen yang diperas oleh flexbox, dan bukan SVG yang di-stretch karena atribut aspect ratio-nya. Di sini elemennya gambar raster biasa, dan yang memampatkan datang dari cascade, dari satu rule yang tidak saya tulis dan tidak saya sadari sedang aktif.

Perbaikannya

Satu deklarasi, ditaruh di selector logonya sendiri:

.site-logo img {
  height: 280px;
  width: auto;
  max-width: none; /* menimpa reset bawaan tema */
}

max-width: none melepas batas atasnya, hitungan auto lolos utuh, dan gambarnya kembali ke 280×280. Wrapper overflow: hidden tetap melakukan tugasnya memotong bagian yang tidak perlu tampil.

Yang saya tahan diri untuk tidak lakukan: menghapus atau melonggarkan reset globalnya. Baris itu ada karena alasan yang sah, yaitu menjaga gambar konten supaya tidak jebol keluar kontainer di layar sempit. Mencabutnya demi satu logo berarti menukar satu bug yang kelihatan dengan puluhan bug yang baru muncul belakangan. Timpa di satu elemen yang memang sengaja melewati lebar parent-nya, bukan di level global yang jadi sandaran semua elemen lain. Header dan footer sama-sama beres begitu selector logonya masing-masing dapat deklarasi ini.

Untuk verifikasi cepat, saya bandingkan rasio asli gambar dengan rasio kotak render-nya:

const el = document.querySelector(".site-logo img");
const box = el.getBoundingClientRect();
console.log(el.naturalWidth / el.naturalHeight, box.width / box.height);

Kalau dua angka itu beda jauh, gambarnya memang sedang didistorsi, dan kamu bisa berhenti mencari-cari di file logonya.

Poin yang saya bawa pulang