İçeriğe geç
LibraryCSS
perspective / transformİleri227 efektte kullanılıyor

perspective ve 3D dönüşümler

CSS'te 3D, üç özelliğin birlikte çalışmasıyla ortaya çıkar: perspective bakış mesafesini, transform-style çocukların kendi derinliklerini koruyup korumayacağını, transform ise elemanın uzaydaki konumunu belirler. Bu üçlü olmadan rotateY(45deg) yazmak elemanı yalnızca yatay olarak sıkıştırır — dönme etkisi görünmez çünkü sahne düz kalır.

Kart çevirme, dönen küp, kitap sayfası ve fareyi takip eden eğim efektlerinin tamamı bu üç bildirimin doğru sırayla kurulmasına dayanır. Rehber perspektifin nereye yazılacağını, dönüşüm sırasının neden önemli olduğunu ve 3D'nin performans bedelini anlatıyor.

perspective: bakış mesafesi nereye yazılır

perspective iki farklı yerde yazılabilir ve ikisi aynı şey değildir. Üst elemana perspective: 800px yazdığında tüm çocuklar *tek bir* kaybolma noktasını paylaşır — yan yana duran kartlar, gerçek bir sahnede olduğu gibi kenardakiler daha eğik görünür. Elemanın kendi transform bildirimine perspective(800px) fonksiyonu olarak yazdığındaysa her eleman kendi kaybolma noktasına sahip olur; ızgaradaki her kart tam karşıdan bakılıyormuş gibi durur.

Değer küçüldükçe etki abartılır. 200px balık gözü gibi keskin bir derinlik verir, 1200px neredeyse ortografik görünür. Kart boyutunun 2–4 katı arasında bir değer çoğu arayüzde doğal durur.

perspective-origin kaybolma noktasını kaydırır. Varsayılan 50% 50% elemanın merkezidir; perspective-origin: 50% 0% yazmak sahneye yukarıdan bakıyormuş hissi verir.

perspective (özellik)
Üst elemana yazılır, tüm çocuklar aynı kaybolma noktasını paylaşır. Sahne kurmak için doğru seçim.
perspective() (fonksiyon)
transform listesinin başında yazılır ve yalnızca o elemanı etkiler. Listedeki ilk fonksiyon olmalıdır; sonra yazılırsa etkisi bozulur.
transform-style: preserve-3d
Çocukların kendi 3D konumlarını korumasını sağlar. Varsayılan flat çocukları üst elemanın düzlemine bastırır ve küp gibi yapıları imkânsız kılar.
cssİki perspektif kurulumunun farkı
/* Paylaşılan sahne: kenardaki kartlar daha eğik görünür */
.izgara {
  perspective: 900px;
  perspective-origin: 50% 40%;
}
.izgara .kart:hover { transform: rotateY(18deg); }

/* Bağımsız sahne: her kart kendi merkezinden bakılmış gibi */
.kart-bagimsiz:hover {
  transform: perspective(900px) rotateY(18deg);
}

Kart çevirme: iki yüz, tek kap

Çevrilen kart üç katmandan oluşur: dış kap perspektifi taşır, iç kap döner, iki yüz iç kabın içinde üst üste durur. Yüzlerin üst üste binmesi position: absolute ve inset: 0 ile sağlanır. Arka yüz baştan rotateY(180deg) ile ters çevrilir, böylece iç kap 180 derece döndüğünde düzelir.

backface-visibility: hidden olmadan iki yüz de aynı anda görünür ve ayna yazı gibi ters metin okunur. Bu bildirim, elemanın arkasını kameraya dönmüş hâlde çizilmesini engeller.

transform-style: preserve-3d iç kapta olmalıdır. Kap flat kalırsa çocukların rotateY(180deg) değeri düzleştirilir ve arka yüz hiç görünmez. Bu, kart çevirme kodunun en sık atlanan satırıdır.

<div class="cevir">
  <div class="cevir-ic">
    <div class="yuz on">Ön yüz</div>
    <div class="yuz arka">Arka yüz</div>
  </div>
</div>
cssKlasik çevrilen kart
.cevir {
  perspective: 1000px;          /* sahne dış kapta */
  width: 240px;
  aspect-ratio: 3 / 4;
}

.cevir-ic {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;  /* olmadan arka yüz hiç görünmez */
  transition: transform 620ms cubic-bezier(0.4, 0.2, 0.2, 1);
}

.cevir:hover .cevir-ic,
.cevir:focus-within .cevir-ic {
  transform: rotateY(180deg);
}

.yuz {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 1rem;
  backface-visibility: hidden;   /* ters metin görünmesin */
  -webkit-backface-visibility: hidden;
}

.on   { background: #1d4ed8; color: #fff; }
.arka { background: #0f172a; color: #e2e8f0; transform: rotateY(180deg); }

Dönüşüm sırası ve transform-origin

transform fonksiyonları soldan sağa uygulanır ve her biri koordinat sistemini kendisiyle birlikte döndürür. rotateY(45deg) translateX(100px) yazmak elemanı önce döndürür, sonra *dönmüş* X ekseninde kaydırır — yani ekranda çapraz gider. translateX(100px) rotateY(45deg) ise önce yatay kaydırır, sonra kendi merkezinde döndürür. İki satır aynı fonksiyonları içerir ama tamamen farklı sonuç verir.

3D küp kurarken bu davranış işine yarar: altı yüzü de aynı translateZ(75px) ile dışa iterek, sadece dönüş açısını değiştirerek yerleştirirsin. Her yüz önce kendi yönüne döner, sonra o yönde ileri itilir.

transform-origin dönüşün ekseninin nerede olduğunu belirler. Kapı gibi açılan bir panel için transform-origin: left center, kitap sayfası için transform-origin: left, aşağıdan yukarı açılan bir kapak için transform-origin: bottom doğru değerlerdir. 3D'de üçüncü bir değer de yazılabilir: transform-origin: 50% 50% -40px ekseni ekranın arkasına taşır.

cssKüpün altı yüzü — tek kalıp, altı açı
.kup {
  position: relative;
  width: 150px;
  aspect-ratio: 1;
  transform-style: preserve-3d;
  animation: kup-don 12s linear infinite;
}

.kup .yuz {
  position: absolute;
  inset: 0;
  border: 1px solid rgb(96 165 250 / 0.5);
  background: rgb(29 78 216 / 0.25);
}

/* Önce döndür, sonra dönmüş eksende 75px (yarı kenar) ileri it */
.kup .on    { transform: rotateY(  0deg) translateZ(75px); }
.kup .sag   { transform: rotateY( 90deg) translateZ(75px); }
.kup .arka  { transform: rotateY(180deg) translateZ(75px); }
.kup .sol   { transform: rotateY(-90deg) translateZ(75px); }
.kup .ust   { transform: rotateX( 90deg) translateZ(75px); }
.kup .alt   { transform: rotateX(-90deg) translateZ(75px); }

@keyframes kup-don {
  to { transform: rotateX(360deg) rotateY(360deg); }
}

Performans ve bilinen tuhaflıklar

3D dönüşümler elemanı kendi compositor katmanına taşır ve GPU'da işlenir; animasyonları bu yüzden ucuzdur. Bedeli bellektir: her katman kendi doku (texture) alanını tutar, dolayısıyla yüzlerce elemana preserve-3d vermek bellek tüketimini gözle görülür artırır.

Katmana alınan elemanlarda metin bazen bulanıklaşır. Sebep, elemanın tam sayı olmayan bir piksel konumuna denk gelmesi ve dokunun yeniden örneklenmesidir. Genişliği çift sayıya yuvarlamak, translateZ(0) yerine will-change: transform kullanmak ya da animasyon bitince dönüşümü kaldırmak sorunu genellikle çözer.

Bilinen bir Safari tuhaflığı: preserve-3d ile overflow: hidden aynı elemanda kullanılamaz. Taşma kırpması 3D bağlamı düzleştirir ve derinlik kaybolur. Kırpma gerekiyorsa bunu ayrı bir dış sarmalayıcıda yap.

Son olarak preserve-3d ile z-index birlikte çalışmaz gibi görünür: 3D bağlamda katman sırası z-index'e değil, elemanların translateZ derinliğine göre belirlenir. Sıralama beklenmedikse çözüm z-index eklemek değil, derinlik değerlerini düzeltmektir.

cssKırpma dış sarmalayıcıda, 3D bağlam içeride
.kirpici {
  overflow: hidden;              /* preserve-3d ile aynı elemanda olamaz */
  border-radius: 1rem;
}

.sahne {
  perspective: 800px;
  transform-style: preserve-3d;
}

Katalogdan canlı örnekler

Aşağıdakiler perspective / transform kullanan gerçek efektler — anlatılan teknik burada çalışır hâlde. Herhangi birine tıklayıp tam kaynağını açabilir, tarayıcı içi editörde değiştirip sonucu anında görebilirsin.

Tarayıcı desteği

Sürüm numaraları özelliğin öneksiz ve varsayılan olarak açık hâle geldiği ilk kararlı sürümü gösterir.

ÖzellikTarayıcılarNot
transform: rotateX / rotateY / translateZChrome 36+, Firefox 16+, Safari 9+, Edge 12+Öneksiz sürüm her yerde çalışır; -webkit- öneki yalnızca çok eski iOS sürümleri için gerekliydi.
transform-style: preserve-3dChrome 36+, Firefox 16+, Safari 9+Safari'de overflow: hidden ile aynı elemanda kullanıldığında 3D bağlam düzleşir.
backface-visibilityChrome 36+, Firefox 16+, Safari 15.4+ (öneksiz)Safari 15.4 öncesi için -webkit-backface-visibility satırını da yaz.
rotate / scale / translate (bağımsız özellikler)Chrome 104+, Firefox 72+, Safari 14.1+transform listesini bölmeden ayrı ayrı animasyonlamayı sağlar; 3D fonksiyonları da kabul eder.

Yaygın hatalar

  • perspective yazılmadan rotateY denemek

    Perspektif yoksa dönüş ortografik hesaplanır ve eleman sadece yatay olarak daralır. Sahneyi kuran perspective bildirimi ya üst elemanda ya da transform listesinin başında olmalı.

  • transform-style: preserve-3d unutmak

    Varsayılan flat tüm çocukları üst elemanın düzlemine bastırır. Kart çevirmede arka yüzün hiç görünmemesinin ve küpün yassı çıkmasının sebebi budur.

  • perspective() fonksiyonunu listenin sonuna yazmak

    rotateY(30deg) perspective(800px) beklendiği gibi çalışmaz; perspektif fonksiyonu transform listesindeki ilk öğe olmalıdır.

  • Aynı elemanda overflow: hidden ve preserve-3d

    Safari'de taşma kırpması 3D bağlamı düzleştirir. Kırpmayı bir dış sarmalayıcıya taşı, 3D bağlamı iç elemanda kur.

  • 3D katmanda bulanık metin

    Kesirli piksel konumu dokunun yeniden örneklenmesine yol açar. Boyutları tam sayıya yuvarla, gereksiz translateZ(0) hilelerinden kaçın ve animasyon bitince dönüşümü kaldır.

Sıkça sorulan sorular

perspective değerini kaç piksel yapmalıyım?
Elemanın genişliğinin 2–4 katı çoğu arayüzde doğal durur. 240 piksellik bir kart için 600–1000px iyi bir aralıktır. Değeri küçültmek derinliği abartır, büyütmek etkiyi düzleştirir; 2000px'in üstünde perspektif neredeyse hiç fark edilmez.
Kartı çevirdim ama arka yüz görünmüyor, neden?
Büyük olasılıkla dönen elemanda transform-style: preserve-3d eksik. Bu bildirim olmadan çocukların 3D dönüşleri düzleştirilir ve arka yüz asla kameraya dönmez. İkinci ihtimal, arka yüze başlangıçta rotateY(180deg) verilmemiş olmasıdır.
3D transform performansı düşürür mü?
Animasyonu ucuzdur çünkü GPU'da compositor katmanında çalışır ve layout tetiklemez. Bedeli bellektir: her 3D katman kendi dokusunu tutar. Onlarca elemanda sorun çıkmaz, yüzlerce elemanda mobil cihazlarda bellek baskısı hissedilir.
translateZ ile scale arasında ne fark var?
scale elemanı düzlemde büyütür; boyutu değişir ama derinliği değişmez. translateZ elemanı kameraya yaklaştırır, perspektif varsa bu da onu büyük gösterir — ama aynı zamanda diğer 3D elemanların önüne geçirir ve sahnedeki sırasını değiştirir.
3D efekti klavyeyle kullanılabilir mi?
Evet, :hover yerine :focus-within kullanırsan kart klavyeyle sekme yapıldığında da çevrilir. Ayrıca prefers-reduced-motion sorgusuyla dönüşü kapatıp iki yüzü çapraz solduran daha yumuşak bir alternatif sunmak iyi bir uygulamadır.

İlgili rehberler

Son güncelleme:

Tüm rehberler