CSS pseudo-class (sözde sınıf), bir seçiciye iki nokta üst üste ile eklenen ve öğeyi belge ağacında yazmayan bir bilgiye göre seçen anahtar kelimedir. button:hover imleç butonun üzerindeyken, input:focus alan odaklandığında, li:nth-child(odd) tek sıradaki liste öğelerinde, input:checked ise işaretli onay kutularında eşleşir. Yani HTML'e sınıf eklemeden, kullanıcının etkileşimine, öğenin kardeşleri arasındaki konumuna ya da form alanının durumuna göre stil verirsiniz.

Bu yazıda en çok kullanılan pseudo-class gruplarını MDN belgelerine dayanarak anlatıyoruz: kullanıcı etkileşimi (:hover, :active, :focus, :focus-visible, :focus-within), bağlantı durumları, ağaç yapısına göre seçim (:first-child, :nth-child() ve akrabaları) ve form durumları. Seçici listesi alan :has(), :is(), :where() ve :not() ayrı bir yazıda: CSS :has(), :is(), :where() ve :not(). Bir öğenin belirli bir parçasını seçen ::before gibi yapılar ise pseudo-element yazısının konusu.

Pseudo-class sözdizimi

Pseudo-class sözdizimi

Bir pseudo-class tek iki nokta (:) ve ardından gelen addan oluşur. Parametre alan türlere fonksiyonel pseudo-class denir ve parantez içinde argüman alırlar, örneğin :nth-child(2n+1). MDN, pseudo-class'ın eklendiği öğeye çapa öğe (anchor element) der: button:hover yazımında çapa button öğesidir. Çapa yazılmazsa pseudo-class her öğeyle eşleşebilir; :hover tek başına imlecin üzerinde olduğu her öğeyi seçer.

Özgüllük açısından bir pseudo-class, bir sınıf seçicisiyle aynı ağırlığı taşır. MDN'nin :root sayfasındaki örnekle: :root ile html aynı öğeyi seçer, ama :root özgüllüğü 0-1-0, html özgüllüğü 0-0-1 değerindedir. Bu, a:hover kuralının sıradan a kuralını neden ezdiğini açıklar. Özgüllük hesaplarının tamamı özgüllük hesaplama yazısında anlatılıyor.

css
/* imleç üzerindeyken bütün butonlar */
button:hover {
  color: blue;
}

/* birden çok pseudo-class zincirlenebilir */
input:focus:invalid {
  border-color: crimson;
}

Kullanıcı etkileşimi: :hover, :active, :focus

:hover, kullanıcı bir işaretleme aygıtıyla öğeyle etkileşime girdiğinde eşleşir; çoğunlukla imleç fare düğmesine basılmadan öğenin üzerine getirildiğinde tetiklenir. MDN dokunmatik ekranlar konusunda açık bir uyarı yapar: Tarayıcıya göre :hover hiç eşleşmeyebilir, dokunduktan sonra bir anlığına eşleşebilir ya da kullanıcı başka bir öğeye dokunana kadar eşleşmeye devam edebilir. Bu yüzden önemli içerikleri yalnızca üzerine gelince görünen bir menüye saklamak, üzerine gelme yeteneği sınırlı ya da hiç olmayan aygıtlarda erişilebilirlik sorununa yol açar.

:active, kullanıcı tarafından etkinleştirilmekte olan bir öğeyi temsil eder. Fare kullanılırken etkinleştirme genellikle birincil düğmeye basıldığı anda başlar ve düğme bırakılana kadar sürer. MDN, çok düğmeli farelerde :active durumunun yalnızca birincil düğme için geçerli olması gerektiğini belirtir. :active çoğunlukla <a> ve <button> üzerinde kullanılır; etkinleştirilen bir öğenin içindeki öğeler ve ilişkili <label> üzerinden etkinleştirilen form öğeleri de bu durumu alabilir.

:focus, odağı almış öğeyi temsil eder. Kullanıcı bir öğeye tıkladığında, dokunduğunda ya da klavyedeki Tab tuşuyla öğeye geldiğinde tetiklenir. Yalnızca odaklanmış öğenin kendisine uygulanır; odaklanmış bir öğeyi içeren kapsayıcıyı seçmek için :focus-within kullanılır. MDN'nin örneğindeki gibi, bir form grubundaki alanlardan herhangi biri odaklandığında grubun tamamını vurgulamak için idealdir.

css
.grup {
  padding: 8px;
  border: 1px solid #cccccc;
}

.grup:focus-within {
  background-color: lightyellow;
  /* gruptaki herhangi bir alan odaklandığında bütün grup vurgulanır */
}

:focus ile :focus-visible farkı

:focus-visible, öğe :focus ile eşleşirken tarayıcının çeşitli sezgisel kurallarla odağın görünür kılınması gerektiğine karar verdiği durumda uygulanır. MDN geçmişi şöyle özetler: Eskiden tarayıcılar odak stillerini yalnızca :focus üzerinden verdiği için fareyle tıklanan her bağlantı ve butonda odak halkası beliriyordu. Bunu çirkin bulan bazı geliştiriciler odak çerçevesini tamamen kaldırdı; bu da klavyeyle gezinen görebilen kullanıcılar için sayfayı erişilemez kıldı.

Bugün tarayıcılar odak göstergesini yalnızca kullanıcıya en çok yardımcı olacağı zaman gösterir. Örneğin bir buton fareyle tıklandığında odak genellikle görsel olarak belirtilmez, ama kullanıcı girişi bekleyen bir metin kutusu odaklandığında belirtilir. Klavyeyle gezinirken ise odak her zaman gösterilir. :focus her zaman odaklanmış öğeyle eşleşir; :focus-visible ise yalnızca kullanıcının odağın nerede olduğunu bilmesi gerektiğinde eşleşir. Bu yüzden odak göstergesinin görünümünü değiştirmek ama ne zaman görüneceğini tarayıcıya bırakmak istiyorsanız :focus-visible doğru seçimdir.

css
button:focus-visible {
  outline: 3px solid #1166ff;
  outline-offset: 2px;
  /* fareyle tıklamada genellikle görünmez, Tab ile gelindiğinde görünür */
}

Bağlantı durumları ve LVHA sırası

Bağlantılar için dört pseudo-class bir arada kullanılır: :link ziyaret edilmemiş, :visited ziyaret edilmiş bağlantıları seçer; ikisi birbirini dışlar. :any-link ise ziyaret durumundan bağımsız olarak href özniteliği olan her <a> ve <area> öğesini seçer. Bu kuralların aynı özgüllükte olduğu durumlarda sonradan yazılan kazanır; bu yüzden MDN kuralları LVHA sırasıyla yazmanızı önerir: :link, :visited, :hover, :active.

css
a:link {
  color: #1166ff;
}

a:visited {
  color: purple;
}

a:hover {
  text-decoration: underline;
}

a:active {
  color: crimson;
  /* en sona yazıldığı için tıklama anında diğerlerini ezer */
}

Sırayı bozarsanız ne olur? Örneğin :hover kuralını :visited kuralından önce yazarsanız, ziyaret edilmiş bir bağlantının üzerine geldiğinizde aynı özgüllükteki :visited sonra geldiği için kazanır ve üzerine gelme rengi görünmez. :visited ayrıca gizlilik nedeniyle sıkı sınırlara tabidir: Yalnızca color, background-color, kenarlık renkleri, outline-color, column-rule-color, text-decoration-color ve text-emphasis-color gibi renk özellikleri değiştirilebilir; renklerin saydamlık bileşeni yok sayılır. MDN, bu özelliklerden yalnızca bazılarının tarayıcıda varsayılan bir değeri olduğunu, diğerlerini değiştirmek için önce :visited dışında bir temel değer vermeniz gerektiğini belirtir.

Ağaç yapısına göre seçim: :first-child ve :nth-child()

Ağaç yapısına göre seçim: :first-child ve :nth-child(): :nth-child(2n+1), :nth-child(5n), :nth-child(n+7), :nth-child(3n+4)

:first-child bir kardeş grubundaki ilk öğeyi, :last-child sonuncuyu, :only-child ise hiç kardeşi olmayan öğeyi seçer. MDN'ye göre :only-child, :first-child:last-child ile aynı öğeleri seçer ama özgüllüğü daha düşüktür. Bu seçiciler listelerin ilk ya da son öğesindeki fazla kenarlığı ya da boşluğu kaldırmak için sık kullanılır.

:nth-child(), öğeleri ebeveynlerinin çocuk listesindeki sıralarına göre seçer. Sıralar 1'den başlar. Argüman olarak odd (1, 3, 5...), even (2, 4, 6...) ya da An+B biçiminde bir formül alır. Formülde A adım büyüklüğü, B başlangıç kaydırması, n ise 0'dan başlayarak tüm negatif olmayan tam sayılardır. Tarayıcı n için 0, 1, 2... değerlerini yerine koyar ve çıkan her pozitif sırayı seçer.

Seçicin = 0, 1, 2, 3 için hesapSeçilen sıralar
:nth-child(2n+1)1, 3, 5, 7Tek sıralar (odd ile aynı)
:nth-child(5n)0, 5, 10, 155, 10, 15 (0 sırası yoktur)
:nth-child(n+7)7, 8, 9, 107. ve sonrası
:nth-child(3n+4)4, 7, 10, 134, 7, 10, 13...
:nth-child(-n+3)3, 2, 1, 0İlk üç öğe

-n+3 formülü özellikle kullanışlıdır: n büyüdükçe sonuç küçülür ve 0 ile negatif değerler sıra olmadığı için seçilmez; geriye ilk üç öğe kalır. İki :nth-child() zincirlenerek aralık da seçilebilir: MDN'nin örneğindeki p:nth-child(n+8):nth-child(-n+15) sekizinci ile on beşinci arasındaki paragrafları seçer.

css
li:nth-child(-n + 3) {
  border: 2px solid orange;
  /* ilk üç öğe çerçevelenir */
}

li:nth-child(even) {
  background-color: lightyellow;
  /* 2, 4, 6... öğeler zebra deseni alır */
}

tr:nth-child(odd) {
  background-color: #f2f2f2;
}

En sık yanılgı: sayım bütün kardeşleri kapsar

MDN'nin özellikle not ettiği bir ayrıntı var: span:nth-child(2n+1) gibi bir yazımda sayım, türü ne olursa olsun bütün kardeş öğeleri kapsar. Bir öğe ancak o sıradaki öğe seçicinin geri kalanıyla da eşleşiyorsa seçilir. Yani beş span arasına bir strong girerse, strong sayıma dahil edilir ama seçilmez; sonraki span öğelerinin sıraları kayar.

html
<div>
  <span>1</span>
  <span>2</span>
  <strong>3</strong>
  <span>4</span>
  <span>5</span>
</div>
css
span:nth-child(2n + 1) {
  color: crimson;
  /* tek sıralar 1, 3, 5: 1 ve 5 numaralı span seçilir,
     3. sıradaki strong olduğu için seçilmez */
}

span:nth-of-type(2n + 1) {
  color: teal;
  /* yalnızca span'ler sayılır: dört span'in 1. ve 3. sırası,
     yani içeriği 1 ve 4 olanlar seçilir */
}

Yalnızca aynı türdeki kardeşleri saymak istiyorsanız :nth-of-type() kullanılır; bu pseudo-class öğeleri aynı etiket adına sahip kardeşleri arasındaki konumlarına göre seçer. Belirli bir sınıftaki öğeleri saymak içinse :nth-child() fonksiyonunun of sözdizimi vardır: :nth-child(-n + 3 of li.onemli), onemli sınıfına sahip öğelerin ilk üçünü seçer. Bu, li.onemli:nth-child(-n + 3) yazımından farklıdır; o yazım, ilk üç çocuk arasında olup aynı zamanda li.onemli ile eşleşen öğeleri seçer. of argümanının tarayıcı desteği için MDN sayfasındaki uyumluluk tablosuna bakın; MDN'nin @supports sayfası bu argümanı kullanan kuralları @supports selector(:nth-child(1n of a, b)) bloğu içine almayı örnekler, böylece desteklemeyen tarayıcılarda kural yarım uygulanmaz.

Form durumları

Form durumları: :checked, :disabled ve :enabled, :required ve :optional, :valid ve :invalid

Form öğelerinin durumuna göre stil vermek için zengin bir pseudo-class ailesi vardır. En sık kullanılanlar şunlardır:

  • :checked: İşaretli radyo düğmesi, onay kutusu ya da bir <select> içinde seçili <option>. MDN, <option> öğelerinin tarayıcılarda değiştirilmiş öğe gibi ele alınabildiğini ve stillenebilme derecesinin tarayıcıdan tarayıcıya değiştiğini not eder.
  • :disabled ve :enabled: Etkinleştirilemeyen ya da odak alamayan öğeler ile etkinleştirilebilen öğeler.
  • :required ve :optional: required özniteliği olan ve olmayan alanlar.
  • :valid ve :invalid: İçeriği doğrulamadan geçen ve geçemeyen alanlar. :invalid form ve fieldset öğelerine de uygulanabilir.
  • :user-valid ve :user-invalid: :valid ve :invalid ile aynı doğrulamayı yapar, ancak yalnızca kullanıcı alanla etkileşime girdikten sonra eşleşir.
  • :placeholder-shown: O anda yer tutucu metnini gösteren <input> ya da <textarea>.

:invalid ile :user-invalid arasındaki fark kullanıcı deneyimi açısından önemlidir. :invalid sayfa yüklenir yüklenmez eşleşir: Boş bir zorunlu alan, kullanıcı daha hiçbir şey yazmadan kırmızı çerçeveyle görünür. MDN'ye göre :user-valid ise kullanıcı alanda bir değişiklik yapıp odağı başka yere taşıdığında, formu göndermeyi denediğinde ya da odaklandığında geçersiz olan değeri geçerli hâle getirdiğinde uygulanır. Zorunlu alanlar ancak kullanıcı onları değiştirdiğinde ya da değiştirilmemiş geçersiz değeri göndermeyi denediğinde geçersiz olarak işaretlenir.

html
<input type="checkbox" id="bulten" />
<label for="bulten">Bültene abone ol</label>
<input type="email" required placeholder="ornek@alan.com" />
<button type="submit" disabled>Gönder</button>
css
input:checked + label {
  font-weight: bold;
}

input:user-invalid {
  border: 2px solid crimson;
  /* kullanıcı alanı doldurup çıkana kadar kırmızı görünmez */
}

input:placeholder-shown {
  border-style: dashed;
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

Örnekteki input:checked + label kuralı, işaretli onay kutusundan hemen sonra gelen etiketi seçer; bu, pseudo-class ile bir birleştiricinin birlikte kullanımıdır ve yalnızca etiket onay kutusunun hemen ardından gelen kardeşiyse çalışır. Bu yüzden HTML'de etiketi onay kutusunun içine değil, hemen arkasına yazdık ve for özniteliğiyle bağladık. Etiketi kutunun önüne koysaydınız kural eşleşmezdi. Birleştiricilerin kuralları için birleştiriciler yazısına, ebeveyni çocuğun durumuna göre seçmek için ise :has() yazısına bakın.

MDN form durumlarında bir erişilebilirlik ilkesini tekrar tekrar vurgular: Geçerli alanı yeşil, geçersiz alanı kırmızı göstermek renk körlüğü olan kullanıcılar için yeterli değildir. Durumu yalnızca renkle değil, açıklayıcı bir metin ya da simgeyle de belirtin. Zorunlu alanlarda da required özniteliği ekran okuyucuların alanın zorunlu olduğunu anlamasını sağlar; görsel işaret yine yalnızca renge dayanmamalıdır.

Uygulamalı mini örnek: erişilebilir bir menü

Öğrendiklerimizi bir gezinme menüsünde birleştirelim. Menü bağlantıları LVHA sırasıyla stilleniyor, klavyeyle gelindiğinde belirgin bir odak göstergesi alıyor, ilk öğede sol boşluk kaldırılıyor ve menü içindeki herhangi bir bağlantı odaklandığında menünün tamamı hafifçe vurgulanıyor.

css
.menu a:link,
.menu a:visited {
  color: #1a1a1a;
}

.menu a:hover {
  color: #1166ff;
}

.menu a:active {
  color: #0b47b3;
}

.menu a:focus-visible {
  outline: 3px solid #1166ff;
  outline-offset: 2px;
}

.menu li {
  margin-inline-start: 1rem;
}

.menu li:first-child {
  margin-inline-start: 0;
}

.menu:focus-within {
  background-color: #f5f8ff;
}

Bu örnekte :hover yalnızca bir renk değişikliği yapıyor, içerik göstermiyor; dokunmatik ekranlarda :hover hiç çalışmasa bile menü kullanılabilir kalıyor. Odak göstergesi outline ile çiziliyor ve :focus-visible sayesinde fareyle tıklayan kullanıcıyı rahatsız etmeden klavye kullanıcısına yol gösteriyor. Geçiş efekti eklemek isterseniz transition yazısına bakabilirsiniz.

Sık yapılan hatalar

  • LVHA sırasını bozmak: :hover ya da :active stilinin görünmemesinin en yaygın nedeni, sonradan yazılan aynı özgüllükteki :visited ya da :link kuralıdır.
  • Odak çerçevesini kaldırmak: outline: none yazıp yerine görünür bir gösterge koymamak klavye kullanıcılarını sayfada kaybettirir.
  • İçeriği yalnızca :hover ile göstermek: Dokunmatik aygıtlarda :hover güvenilir değildir.
  • :nth-child() sayımında yalnızca aynı türü saymak: Sayım bütün kardeşleri kapsar; yalnızca aynı etiketi saymak için :nth-of-type(), belirli bir seçiciye uyanları saymak için of sözdizimini kullanın.
  • Formu açılır açılmaz kırmızı göstermek: :invalid yerine :user-invalid kullanmak, kullanıcı etkileşim kurmadan hata gösterilmesini önler.
  • :visited ile her özelliği değiştirmeye çalışmak: Gizlilik kısıtları nedeniyle yalnızca belirli renk özellikleri uygulanır.

Sık Sorulan Sorular

Pseudo-class ile pseudo-element arasındaki fark nedir?

Pseudo-class tek iki nokta ile yazılır ve öğenin tamamını bir duruma göre seçer (a:hover). Pseudo-element çift iki nokta ile yazılır ve öğenin belirli bir parçasını seçer ya da oluşturur (p::first-line). Ayrıntılar pseudo-element yazısında.

:focus mu :focus-visible mı kullanmalıyım?

Odak göstergesinin görünümünü özelleştiriyorsanız çoğu durumda :focus-visible. Bu pseudo-class tarayıcının odağı ne zaman göstereceğine dair kararını korur, siz yalnızca görünümünü değiştirirsiniz. :focus ise fareyle tıklamada da eşleşir; her odaklanmada uygulanması gereken bir stil için uygundur.

Tablo satırlarına zebra deseni nasıl verilir?

tr:nth-child(odd) ya da tr:nth-child(even) ile. odd, 2n+1 formülüyle, even ise 2n formülüyle aynı satırları seçer.

Bir kapsayıcıyı içindeki alan odaklandığında nasıl vurgularım?

:focus-within ile. Bu pseudo-class, öğenin kendisi ya da alt öğelerinden biri odaklandığında eşleşir. Bir alt öğenin başka bir durumuna (örneğin işaretli olmasına) göre kapsayıcıyı seçmek için :has() gerekir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: CSS öğrenme rehberi · CSS ::before ve ::after · CSS :has(), :is(), :where(), :not() · CSS seçiciler: class, id, attribute · CSS birleştiriciler · CSS özgüllük hesaplama · CSS transition geçiş efektleri