object-fit ve object-position ile Görsel Kesme Kontrolü

Dört ürün kartı, farklı oranlarda kırpılmış fotoğraflar

Bir ürün kartına farklı boyutlarda görsel yükleyince ızgara bozulur. Kimi görsel uzun, kimi kare; tarayıcı hepsini orijinal oranıyla göstermeye çalışınca kart yükseklikleri birbirinden ayrışır, sayfa dağınık görünür. Bunu çözmek için görsele sabit yükseklik verip width: 100% eklemek cazip görünür; ancak görsel ya uzar ya da ezilir. CSS'in bu soruna yanıtı object-fit ve object-position özellikleridir.

Bu iki özellik, bir <img> ya da <video> etiketinin, kendisine ayrılan kutu içinde nasıl davranacağını belirler. Kutu boyutunu içeriğe göre değiştirmek yerine, içeriği kutuya göre şekillendirir. Bu ayrım küçük görünür; ama sonucu farklı HTML yapısı kurmak zorunda kalmamak, JavaScript'e ihtiyaç duymamak ve arka plan görsellerine geçmemek demektir.

object-fit ve object-position yalnızca değişken boyutlu içeriklerin bulunduğu durumlar için değil, tasarımı belirli bir görsel kırpmasına kilitlemeniz gereken her senaryo için geçerlidir. Hero alanındaki büyük görsel, mobilde farklı bir oranda görünebilir; kırpmanın tam ortadan mı yoksa üstten mi yapılacağı kullanıcının göreceği sahneyi doğrudan değiştirir.

Sabit boyutlu kutularda görsel kayması neden olur?

Tarayıcı, bir <img> elemanını varsayılan olarak içerik kutusu (intrinsic size) kadar büyük gösterir. Genişliğe sınır koyarsanız, görsel oranını koruyarak o genişliğe sığar; yükseklik serbestçe değişmeye devam eder. Bir ürün ızgarasında görsellerin boyutları farklıysa, her kartın yüksekliği farklılaşır ve ızgara düzeni dağılır.

img {
  width: 100%;
}

Bu kural genişliği sabitler ama yüksekliği serbest bırakır. 400x300 piksel bir görsel 133px yüksekliğe, 400x600 piksel bir görsel 266px yüksekliğe oturur. İkisi aynı satırdaysa Flexbox ya da CSS Grid, yüksek olanın boyutunu esas alır; kısa görselin altında boşluk kalır.

Çözümün bir yolu görsele sabit yükseklik vermektir:

img {
  width: 100%;
  height: 240px;
}

Tarayıcının varsayılan davranışı object-fit: fill olduğundan görsel yatay veya dikey olarak gerilir. 400x300 piksellik bir ürün fotoğrafı 400x240 kutusunda yassılaşır; yüksek görsel dikey olarak sıkışır. Oran bozulması kaçınılmazdır ve bunu engellemek için başka bir kural gerekir.

object-fit değerleri ve aralarındaki fark

object-fit beş değer alır; her biri farklı bir kırpma ve ölçekleme stratejisi uygular.

cover: Görsel, kutunun her iki boyutunu tamamen kapatacak şekilde ölçeklenir. En-boy oranı korunur. Gerekirse kırpar; ne kadar kırpılacağı görsel ile kutunun oranına bağlıdır. Ürün kartları ve hero alanları için en yaygın tercih budur.

contain: Görsel, kutu içine tamamen sığacak şekilde küçültülür ya da büyütülür. En-boy oranı korunur. Görsel ile kutu oranı uyuşmuyorsa kenar boşlukları oluşur; bu boşluklar genellikle transparan ya da belirlenen arka plan rengiyle dolar. Logo ve ikon gösterimleri için uygundur.

fill: Tarayıcı varsayılanı. Görsel, kutunun tam boyutuna uzatılır; oranlar değişebilir. Web görsellerinde neredeyse hiç istenmez.

none: Görsel orijinal boyutunda kalır, ölçeklenmez. Kutudan büyükse kırpılır; küçükse kenar boşlukları kalır. Belirli bir piksel boyutuna kilitleme gerektiğinde kullanılır.

scale-down: none ile contain'den küçük olanı seçer. Görsel orijinalinden küçülür ama büyütülmez. Küçük ikonlara gereğinden fazla büyüme payı vermek istemediğinizde yararlıdır.

.product-card img {
  width: 100%;
  height: 240px;
  object-fit: cover;
}

Tek kural. Görsel her zaman 240px yükseklikte, kart genişliğinde görünür; kırpılır ama uzatılmaz. Bu, ızgara tutarlılığını çözmek için yeterlidir.

object-position ile odak noktasını yerleştirmek

object-fit: cover kırpmanın nerede yapılacağını belirtmez. Varsayılan olarak merkezi kullanır. Çoğu durumda bu yeterlidir; ama ürün görseli zeminden fotoğraflanmışsa ya da insan yüzü içeren bir içerikte başın üstü kesilebilirse object-position devreye girer.

object-position iki değer alır: yatay ve dikey. Yüzde, piksel ya da anahtar sözcüklerle (top, bottom, left, right, center) tanımlanır.

.hero img {
  width: 100%;
  height: 480px;
  object-fit: cover;
  object-position: center top;
}

Bu kural, kırpma sırasında görselin üst bölümünü ön plana çıkarır. Portre yönlü bir fotoğrafta yüz genellikle üstte bulunur; center top bu durumda yüzü koruyan kırpmayı sağlar.

Yüzde değerleri daha ince ayar sunar:

object-position: 30% 20%;

İlk değer yatay ekseni, ikincisi dikey ekseni kontrol eder. 0% 0% sol üst köşeyi, 100% 100% sağ alt köşeyi ifade eder. Piksel değerleri de geçerlidir:

object-position: 50px 80px;

Bu, odak noktasını sol kenardan 50px, üst kenardan 80px ötede konumlandırır. Belirli bir logonun ya da ürün etiketinin her zaman görünür kalması gerektiğinde bu hassasiyete ihtiyaç duyulur.

Ürün kartı senaryosu: boyut kaymadan ızgara

E-ticaret ürün ızgaralarında görseller farklı kaynaklardan gelir: bazıları kare, bazıları yatay, bazıları dikey. Tüm ürün kartlarının aynı yükseklikte görünmesi için birkaç kural yeterlidir.

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}

.product-card {
  display: flex;
  flex-direction: column;
}

.product-card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
  object-position: center;
}

Bu yapıda kart görselinin boyutu sabitlenir; farklı orandaki görseller aynı kırpma alanına sığar. İçerik bölümü (başlık, fiyat, düğme) her kartta aynı dikey konumdan başlar çünkü görsel alanı sabit yüksekliktedir. Bu yapı olmadan bir kartın görseli 300px, diğerinin 200px yüksekliğe sahip olunca Flexbox'ın align-items: stretch davranışı alt bölümü farklı konumlara iter ve ızgara bozulur.

Sabit yükseklik ile object-fit: cover birleşimi çoğu durumda yeterlidir; ancak görselin hangi bölümünün görünür kalacağını belirlemek gerekirse object-position eklenir. Kıyafet e-ticaretinde ürünün mankenin yüzüyle değil omuz hizasıyla başladığı kareler için object-position: center 20% gibi bir değer daha tutarlı bir sunum yapar.

Hero alanında kırpma: mobil ve masaüstü farkı

Hero görselleri yatay biçimde tasarlanır; ancak mobil ekranlarda kapsayıcı genişliği daralırken yükseklik sabit kalabilir. Bu durumda görsel oranı masaüstüyle aynı kalmaz ve kırpma miktarı artar. Odak noktası görselin ortasındaysa bu genellikle sorun çıkarmaz; ancak önemli öğe (marka adı, ürün, insan yüzü) kenara yerleştirilmişse mobilde kaybolabilir.

.hero {
  position: relative;
  height: 480px;
}

.hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}

@media (max-width: 768px) {
  .hero {
    height: 280px;
  }
  .hero img {
    object-position: 40% center;
  }
}

Medya sorgusuyla her ekran boyutu için ayrı bir odak noktası tanımlanabilir. Masaüstünde görselin üçte birlik üst bölümü görünürken, mobilde yatay odak sola kayar. Tasarım dosyasındaki görsel her kırpma senaryosu için test edilmeden yayına alınırsa mobilde ne görüneceği belirsiz kalır.

Sabit yükseklik yerine orana dayalı yükseklik de tercih edilebilir:

.hero img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

aspect-ratio ile yükseklik genişliğe göre değişir; kapsayıcı daraldıkça görsel de küçülür. Bu yaklaşım piksel cinsinden sabit yükseklik gerektirmeyen düzenler için daha esnektir. Ekran çok dar olduğunda görsel çok küçülebilir; alt sınır için min-height eklenebilir.

object-fit ile background-size arasındaki yapısal fark

CSS arka plan görselleri uzun süredir background-size: cover ve background-position özelliklerini destekler. object-fit çıkmadan önce sabit boyutlu görsel göstermek için <img> etiketi yerine arka plan görseli kullanmak yaygın bir yöntemdi. İki yaklaşım görsel olarak neredeyse aynı sonucu verir; ama aralarındaki fark semantik ve erişilebilirlik açısından önemlidir.

<img> etiketi alt niteliği taşır; ekran okuyucular görseli kullanıcıya tanımlar. SEO tarama botları da <img> etiketlerini içerik görseli olarak işler. Arka plan görseli ise dekoratif kabul edilir; alt niteliği yoktur, botlar tarafından içerik görseli olarak değerlendirilmez.

Arka plan görseli yöntemi tercih edildiğinde bir div'e boyut verilir, görsel CSS'e yazılır:

.card-bg {
  width: 100%;
  height: 240px;
  background-image: url('urun.jpg');
  background-size: cover;
  background-position: center;
}

HTML şablonlarında görsel URL'si değiştiğinde CSS'i değil sadece HTML niteliğini güncellemek yeterli olduğundan, dinamik içerik listeleri için <img> ve object-fit daha kolay yönetilir. Arka plan yöntemi yalnızca gerçekten dekoratif, içerik değeri taşımayan görsellerle kullanılması gereken bir tekniktir.

Ne zaman işe yaramaz ya da ters etki yapar?

Yanlış sezgidir. object-fit: cover her görsel sorununu çözmez; bazı senaryolarda ek sorun yaratır.

İnfografik ve belge görselleri kırpmaya uygun değildir. Tüm içeriğin görünmesi gereken diyagramlarda, tablolarda ve metin içeren görsellerde cover kritik bilgiyi keser. Bu tür görseller için contain ya da serbest boyut daha doğrudur.

object-fit yalnızca <img> ve <video> gibi değiştirilmiş içerik (replaced content) elemanlarında çalışır. Normal bir div'e ya da span'a uygularsanız tarayıcı bu kuralı yok sayar; görsel davranışı değişmez. Bu, özellikle hata ayıklarken karıştırılan bir durumdur: kural varlığına rağmen etkisizdir çünkü yanlış elemana uygulanmıştır.

Küçük ikonlar ve logolar için cover oran korumasına rağmen görsel bozulmasına yol açabilir. 32x32 piksel bir ikon 100x40 piksel kutuya cover ile yerleştirildiğinde büyütülerek kırpılır; piksel tabanlı ikonlarda bu bulanıklık yaratır. contain ya da scale-down çok daha uygun davranır.

object-position değeri görselin kutudan büyük kısmını tamamen dışarı itebilir. object-position: 100% 100% ile sağ alt köşeye sabitleme yapılmışsa ve kırpma miktarı fazlaysa, odaklanmak istenen nesne görüntü alanından çıkabilir. Özellikle farklı oranlarla gelen kullanıcı yüklü görsellerde sabit bir object-position beklenmedik kırpmalara yol açar.

Tarayıcı desteği ve pratik sınırlar

object-fit ve object-position modern tarayıcıların tamamında desteklenir. Masaüstü ve mobil tarayıcıların güncel sürümlerinde herhangi bir ön ek ya da çevrim içi araç gerekmez. Eski sürüm desteği gerekiyorsa durum farklıdır; ancak çoğu projenin hedef kitlesi bu sınırın çok ötesindeki güncel tarayıcıları kullanır.

Internet Explorer 11 object-fit'i desteklemiyordu; bu dönemden kalan eski kod tabanlarında polyfill ya da arka plan yöntemi görmek mümkündür. Aktif olarak IE11 desteği sürdürülmüyorsa bu geçici çözümlerin kaldırılması kodu basitleştirir.

object-fit Flexbox ya da Grid içindeki görsellerde de beklendiği gibi çalışır. Kapsayıcı eleman boyutu değiştiğinde görsel yeniden hesaplanır. Animasyon ve geçişlerle de uyumludur; object-position değeri CSS geçişine sokulabilir:

.product-card img {
  transition: object-position 0.3s ease;
}

.product-card:hover img {
  object-position: center 30%;
}

Hover durumunda odak noktası yavaşça kayar; bu ince bir etkileşim detayı olarak kullanılabilir. Ancak her kart için bu tür animasyon eklenmesi performansa katkı yapmaz, estetik bir tercih meselesidir.

Görseli bir bağlantı içine sardığınızda (a > img) veya kart tamamını tıklanabilir yaptığınızda object-fit davranışı değişmez. Görsel sabit boyutta kalır, kırpma sürer. Bağlantının tıklama alanı görselin gerçek boyutuyla değil CSS'te belirlenen kutu boyutuyla sınırlı olur; bu da kullanıcı deneyimi açısından tutarlıdır.

CSS Grid ile oluşturulmuş asimetrik ızgaralarda bazı kartlar daha büyük görsel alanı alabilir. Bu durumda object-fit: cover her hücre boyutuna göre ayrı ayrı ölçekleme yapar; her hücrenin kendi boyutunu doldurmasını sağlar ve görseller arasında tutarsızlık oluşmaz.

İki özellik birlikte kullanıldığında görsel boyutlandırma sorunlarının büyük bölümü CSS içinde kalır; JavaScript ya da sunucu tarafı kırpma gerektirmez. Yükleme sırasında yükseklik değişmediğinden Cumulative Layout Shift (CLS) değerini düşük tutmak da kolaylaşır; tarayıcı baştan boyutu bilir ve yer ayırır. Bu, özellikle ürün listelerinin başlangıçta boş göründüğü ve görseller yüklenince kaydığı senaryolarda fark yaratır.