İçeriğe geç
LibraryCSS
::before / ::afterOrta2.842 efektte kullanılıyor

::before ve ::after ile katman kurma

::before ve ::after, bir elemanın içeriğinin hemen öncesine ve sonrasına sanal çocuk üretir. Bu çocuklar DOM'da yoktur — HTML'e tek bir etiket bile eklemeden iki fazladan boyama yüzeyi kazanırsın. Bir kart artık tek katman değil üç katmandır: arkada ::before parıltısı, ortada gerçek içerik, üstte ::after çerçevesi.

Katalogdaki gradyan çerçeveler, köşe süsleri, kayan parıltı şeritleri, tırnak işaretleri ve onay kutusu işaretlerinin neredeyse tamamı bu iki sözde elemana dayanır. Bu rehber content kuralını, konumlandırma mantığını, yığın sırasını ve sözde elemanların çalışmadığı durumları anlatıyor.

content: kural değil zorunluluk

Sözde eleman yalnızca content özelliği tanımlıysa oluşur. Değeri boş dize olabilir (content: "") ama bildirim mutlaka bulunmalıdır; yoksa tarayıcı sözde elemanı hiç üretmez ve diğer bütün bildirimlerin sessizce etkisiz kalır. "Kodum neden çalışmıyor" sorularının büyük kısmı unutulmuş bir content satırıdır.

content sadece metin almaz. Sayaç değeri, HTML özniteliğinin içeriği, gradyan görüntüsü ve bunların birleşimi yazılabilir. attr() ile bir data-* özniteliğini okumak, ipucu balonu (tooltip) yazmanın en kısa yoludur.

Varsayılan olarak sözde eleman display: inline'dır. Genişlik, yükseklik ve dikey dolgu vermek istiyorsan display: block ya da konumlandırma (position: absolute) gerekir; ikisi de kutu modelini açar.

csscontent'in dört farklı biçimi
.kart::before  { content: ""; }                       /* boş boyama yüzeyi */
.uyari::before { content: "Dikkat: "; }               /* metin */
.ipucu::after  { content: attr(data-ipucu); }         /* öznitelikten oku */
.bolum::before { content: counter(bolum) ". "; }      /* CSS sayacı */
htmlattr() ile ipucu balonu — fazladan etiket yok
<button class="ipucu" data-ipucu="Panoya kopyala">Kopyala</button>
.ipucu { position: relative; }

.ipucu::after {
  content: attr(data-ipucu);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 0.35rem 0.6rem;
  border-radius: 0.5rem;
  background: #0f172a;
  color: #e2e8f0;
  font-size: 12px;
  opacity: 0;
  pointer-events: none;          /* balon farenin önünü kesmesin */
  transition: opacity 160ms ease;
}

.ipucu:hover::after,
.ipucu:focus-visible::after { opacity: 1; }

Konumlandırma ve yığın sırası

Sözde elemanı elemanın üzerine yaymanın standart kalıbı, üst elemana position: relative, sözde elemana position: absolute ve dört kenara inset: 0 vermektir. inset kısayolu top/right/bottom/left dörtlüsünün yerine geçer ve tek satırda aynı işi yapar.

Yığın sırası önemli bir ayrıntı içerir: ::before varsayılan olarak içeriğin *altında* değil, aynı yığın bağlamında ondan önce boyanır — yani içerik metni onun üzerinde kalır. Ama sözde elemana arka plan verip mutlak konumlandırdığında metni kapatabilir. Arkaya göndermek için z-index: -1 yeterlidir; ancak bu, üst elemanın yeni bir yığın bağlamı oluşturmaması şartıyla çalışır. Üst elemanda opacity: 0.99, transform, filter veya isolation: isolate varsa -1 değeri elemanın arka planının altına inemez ve katman kaybolur.

Güvenli yöntem negatif z-index'ten kaçınmaktır: içeriği bir sarmalayıcıya alıp ona position: relative; z-index: 1 vermek, sözde elemanı ise z-index: 0da bırakmak her yığın bağlamında öngörülebilir çalışır.

cssGradyan çerçeve — iki sözde eleman, tek etiket
.cerceve {
  position: relative;
  z-index: 0;                    /* kendi yığın bağlamını kur */
  padding: 1.5rem;
  border-radius: 1rem;
  background: #0c1017;
}

/* Dıştaki gradyan katman: 1px taşarak çerçeve gibi görünür */
.cerceve::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;        /* köşe yarıçapını üst elemandan al */
  background: linear-gradient(135deg, #3b82f6, #1d4ed8 60%, #0ea5e9);
}

/* Üstteki parıltı: içeriğin üzerinde ama tıklamayı engellemiyor */
.cerceve::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(120deg, rgb(255 255 255 / 0.14), transparent 40%);
  pointer-events: none;
}

Kayan parıltı: sözde elemanı animasyonlamak

Sözde elemanlar tam anlamıyla animasyonlanabilir. Kart üzerinde soldan sağa geçen ışık şeridi, dar bir gradyanın translateX ile kartın dışından içeri sürülmesiyle yapılır. Kabın overflow: hidden olması şeridin kenarlardan taşmasını engeller.

Şeridi eğik göstermek için rotate eklenir; şerit döndüğünde köşegen uzunluğu genişliği aştığı için width değerini kabın genişliğinden büyük tutmak gerekir, aksi halde şerit köşelerde kesik görünür.

Aynı teknik ::before ile alt katman, ::after ile üst katman ayrımı yapıldığında iki yönlü parıltılar, çift çerçeveler ve tarama çizgileri üretir. İki sözde eleman farklı animation-delay alırsa tek elemandan iki fazlı hareket çıkar.

cssSoldan sağa geçen ışık şeridi
.parilti {
  position: relative;
  overflow: hidden;              /* şerit kenardan taşmasın */
  border-radius: 0.9rem;
  background: #121722;
  padding: 1.25rem;
}

.parilti::after {
  content: "";
  position: absolute;
  top: -50%;
  left: -60%;
  width: 45%;
  height: 200%;
  background: linear-gradient(
    90deg,
    transparent,
    rgb(255 255 255 / 0.16),
    transparent
  );
  transform: rotate(18deg);
  pointer-events: none;
}

.parilti:hover::after {
  animation: gec 900ms ease-out;
}

@keyframes gec {
  to { left: 130%; }
}

Nerede çalışmaz, ne zaman kullanılmaz

Sözde elemanlar yalnızca içerik kutusu olan elemanlarda üretilir. img, input, br, hr, iframe ve video gibi değiştirilmiş (replaced) elemanlarda ::before / ::after çalışmaz; çünkü bu elemanların içeriği tarayıcı tarafından dışarıdan getirilir ve içine bir şey yerleştirilemez. Bir input'a işaret koymak gerekiyorsa bunu ona ait label üzerinde ya da bir sarmalayıcıda yaparsın — katalogdaki onay kutusu ve anahtar efektlerinin label etrafında kurulmasının sebebi budur.

Erişilebilirlik açısından kritik kural: content ile üretilen metin ekran okuyucular tarafından okunabilir ama davranışı tarayıcıdan tarayıcıya değişir ve kullanıcı onu seçemez, kopyalayamaz, arama yapamaz. Bu yüzden anlam taşıyan metni asla content içine koyma. Süs karakterleri ve ikonlar için ise tersini yap: content: "→" yazıp ekran okuyucunun bunu "sağ ok" diye okumasını engellemek için boş bir alternatif metin ver.

Baskı ve arama motoru tarafında da aynı ilke geçerli: Google content metnini indekslemeyi garanti etmez. Başlık, fiyat ve bağlantı metni HTML'de olmalıdır.

cssSüs karakterini ekran okuyucudan gizle
.bag::after {
  content: "→" / "";             /* eğik çizgiden sonrası alternatif metin */
  margin-left: 0.35rem;
}

/* Alternatif metin sözdizimini desteklemeyen tarayıcılar için yedek */
@supports not (content: "x" / "y") {
  .bag::after { content: "→"; speak: never; }
}

Katalogdan canlı örnekler

Aşağıdakiler ::before / ::after 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
::before / ::after (iki iki nokta)Chrome 1+, Firefox 1.5+, Safari 4+, Edge 12+Tek iki noktalı `:before` yazımı da hâlâ geçerlidir ama sözde sınıflardan ayırmak için iki iki nokta tercih edilir.
content: attr()Tüm modern tarayıcılarYalnızca dize değeri döndürür; `attr(data-x, px)` gibi tip dönüşümü henüz yaygın desteklenmiyor.
content alternatif metni ("x" / "alt")Chrome 77+, Safari 17.4+Firefox'ta desteklenmiyor; desteklenmeyen tarayıcı bildirimin tamamını atar, o yüzden @supports yedeği yaz.
inset kısayoluChrome 87+, Firefox 66+, Safari 14.1+Dört kenarı ayrı yazmakla aynı sonucu verir; eski tarayıcı için top/right/bottom/left yedeği eklenebilir.

Yaygın hatalar

  • content bildirimi unutuldu

    content yoksa sözde eleman hiç oluşmaz ve diğer tüm bildirimler etkisiz kalır — hata da verilmez. Boş katman için content: "" yaz.

  • z-index: -1 katmanı görünmez yapıyor

    Üst elemanda transform, filter, opacity < 1 veya isolation varsa yeni bir yığın bağlamı oluşur ve negatif z-index o bağlamın dışına çıkamaz. İçeriği sarmalayıp pozitif z-index vermek daha güvenli.

  • img ve input üzerinde denemek

    Değiştirilmiş elemanlarda sözde eleman üretilmez. Görsele çerçeve gerekiyorsa bir sarmalayıcı div, forma işaret gerekiyorsa label kullan.

  • Üstteki katman tıklamayı yutuyor

    inset: 0 ile yayılan bir ::after, altındaki bağlantı ve butonların tıklanmasını engeller. Süs katmanlarına daima pointer-events: none ekle.

  • border-radius mirası alınmadı

    Mutlak konumlu sözde eleman üst elemanın köşe yarıçapını devralmaz; yuvarlak kartın köşelerinden kare bir katman taşar. border-radius: inherit tek satırda çözer.

Sıkça sorulan sorular

::before ile :before arasında fark var mı?
İşlev olarak yok, ikisi de aynı sözde elemanı seçer. İki iki nokta CSS3 ile gelen ve sözde elemanı sözde sınıftan ayıran doğru yazımdır. Tek iki nokta yalnızca çok eski IE sürümleri için gerekliydi; bugün tercih edilen yazım ::before.
Bir elemana ikiden fazla sözde eleman ekleyebilir miyim?
Standart CSS'te eleman başına ::before ve ::after olmak üzere iki tane vardır. Daha fazla katman gerekiyorsa iç içe elemanların sözde elemanlarını kullanırsın: kart, kartın içindeki başlık ve gövde ayrı ayrı ikişer katman sunar.
Sözde elemanı JavaScript ile değiştirebilir miyim?
Doğrudan seçemezsin çünkü DOM'da düğüm olarak bulunmazlar. Pratik yol, üst elemanda bir CSS değişkeni veya data özniteliği güncellemektir: content: attr(data-etiket) ya da background: var(--renk) yazarsan JavaScript tarafında yalnızca özniteliği değiştirmen yeterli olur.
content içindeki metin SEO'ya sayılır mı?
Güvenilir değil. Arama motorları CSS ile üretilen metni indeksleme garantisi vermez ve kullanıcı bu metni seçip kopyalayamaz. Anlam taşıyan her metin HTML'de bulunmalı; content yalnızca süs, ikon ve sayaç için kullanılmalı.
Sözde eleman animasyonlanabilir mi?
Evet, tam bir eleman gibi davranır: transition, animation, transform ve filter hepsi çalışır. Yalnızca content değerinin kendisi geçişlerde animasyonlanamaz — metni değiştirmek istiyorsan iki ayrı sözde elemanı çapraz soldurmak gerekir.

İlgili rehberler

Son güncelleme:

Tüm rehberler