- Moderatör
- #1
- Kayıtlı
- 1 Yıl 9 Ay 26 Gün
- Katılım
- 10 Ocak 2025
- Konular
- 163
- Mesajlar
- 257
- Tepkime puanı
- 36
- Online süresi
- 11h 19m
- Puan
- 53
- Konum
- Türkiye
- Web sitesi
- www.zyncra.shop
JavaScript'siz Koşullu Stil: CSS:has ile Ebeveyni, Önceki Kardeşi ve Hatalı Form Alanını Seçen Seçiciler Yazmak
1. Çocuğuna bakarak ebeveynini boyayan CSS seçicisi :has() ile kart, form, menü ve liste düzenlerini JavaScript'e el atmadan yönetin
İçinde alt başlık olan kartın arka planı değişsin, formda hatalı alan varsa çevresindeki çerçeve kızarsın, bir karta fare gelince yanındakiler solsun istiyorsunuz. Yıllardır bunun cevabı aynıydı: bir script yaz, durumu yakala, ebeveyne sınıf ekle, sonra o sınıfı CSS'te karşıla. Kod uzar, sınıf eklemeyi unuttuğunuz bir yerde görünüm bozulur.
1. Adım: :has() Seçicisi Nedir, Hangi Tarayıcılarda Çalışır ve @supports ile Güvenle Nasıl Kullanılır
İki ayrıntıyı baştan bilin.
2. Adım: Alt Elemanına Bakarak Ebeveyni Boyamak: h2 Varsa, İkisi Birden Varsa, Biri Varsa ve Hiç Yoksa
En basit kullanım, bir blog kartının başlık alanını içindeki elemanlara göre değiştirmek. Markup şöyle olsun:
Dört durumun dördü de tek satırlık seçiciyle karşılanıyor:
Dört kuralın özgüllüğü (specificity) aynı olduğu için aynı özelliği değiştirirlerse sonuncusu kazanır. Denerken her seferinde birini bırakın, ya da farklı özellikler (arka plan, kenarlık) kullanın. Virgüllü sürümün "veya", zincirlenen sürümün "ve" anlamına geldiğini aklınızda tutun.
3. Adım: Sayfanın Herhangi Bir Yerini Seçmek: Onay Kutusuyla Bulanıklaştırma ve Hero Bölümü Varsa Menü Logosunu Gizlemek
Seçici ebeveynle sınırlı değil.
Burada bir düzeltme var. Logoyu gizlemek için
4. Adım: Önceki Kardeşi Seçmek ve Form Hatalarını :user-invalid ile Etiket ve Fieldset Üzerinde Göstermek
CSS'te şimdiye kadar yalnızca sonraki kardeşi seçebiliyorduk.
5. Adım: Slayt Düzenlerini İçeriğe Göre Değiştirmek, Hover'da Diğer Kartları Soluklaştırmak ve Çocuk Sayısına Göre Grid Kurmak
Slayt benzeri
Sıradaki iki örnek liste davranışı. Birincisinde fareyle üzerine gelmediğiniz kartlar sönüyor, ikincisinde üç ve üzeri çocuğu olan liste ızgaraya dönüyor:
Hover örneğini
6. Adım: Boş Elemanları Yakalamak, Açılır Menü Öğelerini İşaretlemek ve PNG Görselin Arka Planını Ayarlamak
Üç küçük ama işe yarar örnek daha:
Boş eleman örneği özellikle React gibi bir kütüphaneyle çalışırken, bileşen farkında olmadan boş bir
7. Adım: Canlıya Almadan Önce Performans, Erişilebilirlik ve Tarayıcı Kontrol Listesi
Yayına çıkmadan şu listeden geçin:
Bir sonraki adım olarak sitenizdeki en uzun doğrulama script'ini bulun ve yalnızca görünümle ilgili kısmını
Sıkça Sorulan Sorular (SSS)
Kategori: cPanel / Web • ⏱ Okuma Süresi: ~7 dk •
Kod: CSS
1. Çocuğuna bakarak ebeveynini boyayan CSS seçicisi :has() ile kart, form, menü ve liste düzenlerini JavaScript'e el atmadan yönetin
İçinde alt başlık olan kartın arka planı değişsin, formda hatalı alan varsa çevresindeki çerçeve kızarsın, bir karta fare gelince yanındakiler solsun istiyorsunuz. Yıllardır bunun cevabı aynıydı: bir script yaz, durumu yakala, ebeveyne sınıf ekle, sonra o sınıfı CSS'te karşıla. Kod uzar, sınıf eklemeyi unuttuğunuz bir yerde görünüm bozulur.
:has() ile bu işin büyük kısmı doğrudan stil dosyasına geçiyor. Aşağıda bunu küçük örneklerle, çalışır halde adım adım gösteriyorum.1. Adım: :has() Seçicisi Nedir, Hangi Tarayıcılarda Çalışır ve @supports ile Güvenle Nasıl Kullanılır
:has() ilişkisel bir seçicidir ve "içinde şu olan eleman" diye sorar. Düzenli ifadelerdeki ileriye bakma (lookahead) mantığına benzer: seçtiğiniz eleman, parantez içindeki koşulu sağlıyorsa kural uygulanır. Chrome 105 ile geldi, Safari 15.4'ten beri var, Firefox ise 121 sürümüyle (2023 sonu) listeye katıldı. Yani bugün büyük tarayıcıların hepsinde çalışıyor. Yine de hedef kitlenizde eski cihaz çoksa kuralı @supports selector() içine almak ucuz bir sigortadır.CSS:
/* varsayılan görünüm her tarayıcıda kalır */
.header {
background-color: #f1f1f1;
}
/* :has() destekleniyorsa devreye girer */
@supports selector(:has(*)) {
.header:has(h2) {
background-color: #d3d3d3;
}
}İki ayrıntıyı baştan bilin.
:has() "affedici" bir seçici listesi değildir: içine virgülle yazdığınız seçicilerden biri geçersizse kuralın tamamı düşer. Ayrıca :has() içinde bir :has() daha kullanamazsınız.
2. Adım: Alt Elemanına Bakarak Ebeveyni Boyamak: h2 Varsa, İkisi Birden Varsa, Biri Varsa ve Hiç Yoksa
En basit kullanım, bir blog kartının başlık alanını içindeki elemanlara göre değiştirmek. Markup şöyle olsun:
HTML:
<header class="header">
<h1 class="title">Yazı Başlığı</h1>
<h2 class="subtitle">Alt başlık</h2>
<blockquote>Kısa bir alıntı</blockquote>
</header>Dört durumun dördü de tek satırlık seçiciyle karşılanıyor:
CSS:
/* alt başlık varsa */
.header:has(h2) { background-color: darkgrey; }
/* alt başlık ve alıntı birlikte varsa */
.header:has(h2):has(blockquote) { background-color: hotpink; }
/* ikisinden en az biri varsa */
.header:has(h2, blockquote) { background-color: lightsalmon; }
/* alt başlık hiç yoksa */
.header:not(:has(h2)) { background-color: lightpink; }Dört kuralın özgüllüğü (specificity) aynı olduğu için aynı özelliği değiştirirlerse sonuncusu kazanır. Denerken her seferinde birini bırakın, ya da farklı özellikler (arka plan, kenarlık) kullanın. Virgüllü sürümün "veya", zincirlenen sürümün "ve" anlamına geldiğini aklınızda tutun.
3. Adım: Sayfanın Herhangi Bir Yerini Seçmek: Onay Kutusuyla Bulanıklaştırma ve Hero Bölümü Varsa Menü Logosunu Gizlemek
Seçici ebeveynle sınırlı değil.
body üzerinden "sayfada şu varsa, şuranın stilini değiştir" diyebilirsiniz. İlk örnekte bir onay kutusu işaretlenince cevap bulanıklaşıyor, hiç script yok:CSS:
/* kutu işaretliyse cevabı bulanıklaştır */
body:has(input.blur-answer:checked) .answer {
filter: blur(5px);
}
/* hero içinde logo varsa menüdeki logoyu gizle */
body:has(.hero-with-logo) .nav-bar .logo {
visibility: hidden; /* yer kaplar, görünmez */
}Burada bir düzeltme var. Logoyu gizlemek için
opacity: 0 kullanan örnekler görürsünüz. Eleman düzende yerinde kalır diye mantıklı görünse de odak alabilir ve ekran okuyucuya okunabilir. visibility: hidden yerini korur, erişilebilirlik ağacından da çıkarır. Bulanıklaştırma ise yalnızca görsel bir efekttir, ekran okuyucu "42"yi yine okur. Gerçekten saklanması gereken bir bilgi için bu yöntem yetmez.
4. Adım: Önceki Kardeşi Seçmek ve Form Hatalarını :user-invalid ile Etiket ve Fieldset Üzerinde Göstermek
CSS'te şimdiye kadar yalnızca sonraki kardeşi seçebiliyorduk.
:has() bunu tersine çeviriyor. *:has(+ .select-before), "hemen ardından .select-before gelen her elemanı seç" demek. Bunun en kullanışlı hali form doğrulamasında:HTML:
<label for="url-input">Adres girin:</label>
<input type="url" id="url-input" />CSS:
/* input hatalıysa hemen öncesindeki label kızarsın */
label:has(+ #url-input:user-invalid) { color: crimson; }
/* input label'ın içindeyse */
label:has(input:user-invalid) { background-color: #fde2e2; }
/* gruptaki herhangi bir alan hatalıysa */
fieldset:has(input:user-invalid) { border: 1px solid red; }:invalid yerine :user-invalid seçmemin nedeni şu: ilki sayfa açılır açılmaz boş zorunlu alanları kırmızıya boyar, ikincisi kullanıcı alanla etkileşime girdikten sonra devreye girer. Tarayıcının kendi doğrulaması (type="url", required, minlength) çalışmaya devam ediyor, siz yalnızca görünümü bağlıyorsunuz.5. Adım: Slayt Düzenlerini İçeriğe Göre Değiştirmek, Hover'da Diğer Kartları Soluklaştırmak ve Çocuk Sayısına Göre Grid Kurmak
Slayt benzeri
article bloklarında düzeni içeriğe göre seçebilirsiniz. Burada bir hata düzeltmem gerekiyor: bu örneklerde > is:(h1, h2) gibi yazılmış, geçersiz bir seçici dolaşıyor. Doğrusu :is(h1, h2). Ayrıca h2 + img kuralı iki görselli slaytı da yakaladığı için :last-child ile daralttım.CSS:
/* tek başına başlık olan slayt */
article:has(> :is(h1, h2):only-child) {
grid-template-areas: "heading heading";
}
/* başlık ve tek görsel */
article:has(> h2 + img:last-child) {
grid-template-areas: "heading heading" "image1 image1";
}
/* başlık ve iki görsel */
article:has(> h2 + img + img) {
grid-template-areas: "heading heading" "image2 image3";
}Sıradaki iki örnek liste davranışı. Birincisinde fareyle üzerine gelmediğiniz kartlar sönüyor, ikincisinde üç ve üzeri çocuğu olan liste ızgaraya dönüyor:
CSS:
/* sadece fare destekleyen cihazlarda */
@media (hover: hover) {
.card-list:has(.card:hover) .card:not(:hover) {
opacity: 0.4;
scale: 0.9;
}
}
/* üçüncü çocuk varsa ızgaraya geç */
.card-list:has(> :nth-child(3)) {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.card-list:has(> :nth-child(3)) > :last-child {
grid-column: 1 / -1;
}Hover örneğini
@media (hover: hover) içine aldım, çünkü dokunmatik ekranda "hover" takılı kalıp kartları soluk bırakabiliyor. Aynı fikir tablo satırlarında da işe yarar.
6. Adım: Boş Elemanları Yakalamak, Açılır Menü Öğelerini İşaretlemek ve PNG Görselin Arka Planını Ayarlamak
Üç küçük ama işe yarar örnek daha:
CSS:
/* içi boş doğrudan çocuğu olan kutuyu çerçevele */
article:has(> :empty) {
border: 1px dotted crimson;
}
/* alt menüsü olan öğeye ok ekle */
.menu-dropdown li:has(ul) > a::after {
content: " \25BE";
}
/* PNG görselin saydam zeminine renk ver */
.display:has(img[src$=".png"]) img {
background: linear-gradient(90deg, #e8e7e8, #c9ccd0);
}Boş eleman örneği özellikle React gibi bir kütüphaneyle çalışırken, bileşen farkında olmadan boş bir
p üretince hata ayıklamayı kolaylaştırıyor. İçinde boşluk karakteri bulunan eleman :empty sayılmaz, bunu aklınızda tutun. Menü okunda kaynak örnekler emoji kullanıyor. Ben yerine \25BE kaçış kodunu koydum, çünkü emoji fontu cihazdan cihaza değişir. Menüdeki a etiketini kendi markup'ınıza göre uyarlayın.7. Adım: Canlıya Almadan Önce Performans, Erişilebilirlik ve Tarayıcı Kontrol Listesi
Yayına çıkmadan şu listeden geçin:
- Seçiciyi dar tutun.
body:has()ve*:has()her DOM değişiminde geniş bir alanı yeniden değerlendirebilir. Mümkünse hedefe en yakın ortak ataya bağlayın, büyük listelerde DevTools Performance sekmesiyle ölçün. - Bilgiyi yalnızca görsel efektle taşımayın. Kırmızı çerçeve ya da blur, ekran okuyucu kullananlara bir şey söylemez; hata metni ve
aria-describedbyile destekleyin. - Eski tarayıcı ihtimaline karşı kritik düzenleri
@supports selector(:has(*))ile sarın ve varsayılan görünümü bozulmayacak şekilde yazın. - Chrome, Firefox ve Safari'de formu elle deneyin;
:user-invaliddavranışı etkileşim sırasına göre küçük farklar gösterebilir. - Hover tabanlı kuralları
@media (hover: hover)içinde tutun, klavye kullanıcıları için:focus-withinkarşılığını da ekleyin. - Aynı özelliği değiştiren birden çok
:has()kuralı yazdıysanız sıralarını ve özgüllüklerini kontrol edin.
Bir sonraki adım olarak sitenizdeki en uzun doğrulama script'ini bulun ve yalnızca görünümle ilgili kısmını
fieldset:has(input:user-invalid) gibi bir kurala taşımayı deneyin. Takıldığınız seçiciyi ya da tarayıcıda farklı davranan bir durumu konunun altına yazarsanız birlikte bakalım.Sıkça Sorulan Sorular (SSS)
Soru 1: Paylaşılan CSS örneği canlı (production) ortamda kullanılabilir mi?
Evet. Konudaki kod bloğu bellek güvenliği, hata yakalama ve performans kriterleri gözetilerek hazırlanmıştır; kendi proje mimarinize uyarlayarak doğrudan kullanabilirsiniz.
Soru 2: JavaScript'siz Koşullu Stil: CSS:has ile Ebeveyni, Önceki Kardeşi ve Hatalı Form Alanını Seçen Seçiciler Yazmak uygulamasında en sık yapılan hata nedir?
Girdi doğrulamasını (validation) ve zaman aşımı/kaynak sınırlarını varsayılan değerlerde bırakmaktır. Rehberdeki yapılandırma adımlarını eksiksiz uygulayarak olası darboğazları önleyebilirsiniz.
Evet. Konudaki kod bloğu bellek güvenliği, hata yakalama ve performans kriterleri gözetilerek hazırlanmıştır; kendi proje mimarinize uyarlayarak doğrudan kullanabilirsiniz.
Soru 2: JavaScript'siz Koşullu Stil: CSS:has ile Ebeveyni, Önceki Kardeşi ve Hatalı Form Alanını Seçen Seçiciler Yazmak uygulamasında en sık yapılan hata nedir?
Girdi doğrulamasını (validation) ve zaman aşımı/kaynak sınırlarını varsayılan değerlerde bırakmaktır. Rehberdeki yapılandırma adımlarını eksiksiz uygulayarak olası darboğazları önleyebilirsiniz.

