CSS @supports kuralı, tarayıcının belirli bir CSS özelliğini, değerini ya da seçicisini destekleyip desteklemediğini sınar ve içindeki stilleri yalnızca sonuç doğruysa uygular. MDN bu kullanıma özellik sorgusu (feature query) der. Örneğin @supports (display: grid) bloğuna yazdığınız kurallar yalnızca display: grid bildirimini geçerli kabul eden tarayıcılarda çalışır; diğerleri bloğu tamamen atlar.

Özellik sorguları aşamalı geliştirme (progressive enhancement) için kullanılır: Herkese çalışan bir temel çözüm yazarsınız, yeni özellikleri anlayan tarayıcılara ise daha gelişmiş bir sürüm sunarsınız. Bu yazıda bildirim ve fonksiyon sözdizimini, not, and, or operatörlerini, selector(), font-tech(), font-format() ve at-rule() fonksiyonlarını, @import içindeki supports() koşulunu ve özellik sorgularının sınırlarını anlatıyoruz.

Temel sözdizimi ve kuralın yeri

Temel sözdizimi ve kuralın yeri

@supports kuralı bir destek koşulu ve bir kural bloğundan oluşur. Koşul iki biçimde yazılabilir: özellik: değer bildirimi ya da bir fonksiyon. MDN'ye göre kural ya stil dosyasının en üst düzeyinde ya da başka bir koşullu grup kuralının (örneğin @media) içinde bulunmalıdır. Yerel CSS nesting ile bir stil kuralının içine de yazılabilir; bu kullanım nesting yazısında anlatılıyor.

css
/* temel düzen herkes için */
.flex-container > * {
  padding: 0.3em;
  float: left;
}

/* flex destekleniyorsa geliştirilmiş düzen */
@supports (display: flex) {
  .flex-container {
    display: flex;
  }

  .flex-container > * {
    float: none;
  }
}
/* sonuç: flex anlamayan tarayıcı float düzenini, anlayan flex düzenini kullanır */

Bildirim sözdiziminde bildirim mutlaka parantez içinde yazılmalıdır. @supports display: grid geçersizdir; doğrusu @supports (display: grid) biçimidir. Bloğun içine stil kurallarının yanında @keyframes gibi başka at-rule'lar da yerleştirilebilir.

Değer seçimi neden önemli

Yalnızca bir özelliğin var olup olmadığını öğrenmek istiyorsanız MDN'ye göre çoğu durumda hangi değeri yazdığınızın önemi yoktur; herhangi bir geçerli değer işinizi görür. Örneğin row-gap desteğini @supports (row-gap: 10px) ile sınayabilirsiniz. Değer, bir özelliğe sonradan eklenmiş yeni bir değeri sınamak istediğinizde önem kazanır. color: red CSS1'den beri her yerde desteklenir; ancak aynı color özelliğine eklenmiş göreli renk sözdizimi ya da AccentColor gibi sistem renkleri her tarayıcıda olmayabilir. Özellik sorgusu özellik ve değer çiftini birlikte sınadığı için yeni değerleri de ayrı ayrı yakalayabilirsiniz.

css
@supports (color: AccentColor) {
  p {
    color: green;
    border: 2px solid;
  }
}

@supports not (color: AccentColor) {
  p {
    color: red;
  }
}
/* sonuç: AccentColor geçerliyse yeşil ve kenarlıklı, değilse kırmızı metin */

Buradan çıkan bir uyarı da var: Desteklenen bir özelliği geçersiz bir değerle sınarsanız koşul yanlış döner. @supports (display: gird) gibi bir yazım hatası, tarayıcı grid desteklese bile bloğu devre dışı bırakır. Sistem renkleri dark mode yazısında, göreli renk sözdizimi ise color-mix ve göreli renkler yazısında anlatılıyor.

Mantıksal operatörler: not, and ve or

not bir ifadenin önüne gelerek sonucunu tersine çevirir: @supports not (transform-origin: 10em 10em 10em), tarayıcı bu değeri geçersiz sayıyorsa doğru olur. En üst düzeyde not için ek parantez gerekmez, ama and ya da or ile birleştirirken parantez zorunludur. and iki ifadenin birlikte doğru olmasını, or en az birinin doğru olmasını ister. Aynı operatör art arda ek parantez olmadan tekrarlanabilir.

css
/* ikisi birden */
@supports (display: grid) and (shape-outside: circle()) { /* ... */ }

/* biri yeterli: standart ad veya önekli ad */
@supports (text-stroke: 10px) or (-webkit-text-stroke: 10px) { /* ... */ }

/* hiçbiri desteklenmiyorsa yedek */
@supports not ((text-align-last: justify) or (-moz-text-align-last: justify)) { /* ... */ }

/* iç içe not da geçerli */
@supports (display: grid) and (not (display: inline-grid)) { /* ... */ }

MDN'nin bu bölümdeki en önemli notu şudur: and ile or aynı koşulda birlikte kullanılıyorsa uygulanma sırasını parantezle belirtmeniz gerekir. Belirtmezseniz koşul geçersiz olur ve kuralın tamamı yok sayılır. Yani (a) and (b) or (c) yazımı geçersizdir; niyetinize göre ((a) and (b)) or (c) ya da (a) and ((b) or (c)) yazmalısınız.

Önekli adları or ile birlikte sınamak, MDN'nin özellik sorguları rehberinde de önerilen bir desendir: Standart özelliği ve önekli sürümlerini aynı koşulda listelediğinizde tarayıcı hangisini tanıyorsa koşul doğru olur. Önekleri yalnızca belgede gösterildikleri durumlarda kullanmak iyi bir ilkedir; bu serideki örnekler de bu nedenle önekleri yalnızca MDN örneklerinden aldığımız yerlerde içerir.

Fonksiyon sözdizimi: selector(), font-tech(), font-format() ve at-rule()

Fonksiyon sözdizimi: selector(), font-tech(), font-format() ve at-rule(): selector(), font-tech(), font-format(), at-rule()

Bazı şeyler bir özellik ve değer çifti olarak sınanamaz. Bunlar için @supports fonksiyon sözdizimini sunar. selector() tarayıcının bir seçici sözdizimini destekleyip desteklemediğini sınar; MDN'nin örneği selector(h2 > p) ile alt öğe birleştiricisini denetler. Bu fonksiyon özellikle :has() gibi ilişkisel seçiciler için kullanışlıdır.

css
/* :has() anlamayan tarayıcı bu kuralı kendiliğinden atlar */
ul:has(> li li) {
  /* :has() destekleniyorsa uygulanır */
}

/* :has() desteklenmiyorsa yedek */
@supports not selector(:has(a, b)) {
  ul > li,
  ol > li {
    /* daha geniş eşleşen yedek kurallar */
  }
}

font-tech() bir yazı tipi teknolojisinin, font-format() ise bir yazı tipi biçiminin desteklenip desteklenmediğini sınar. at-rule() bir at-rule'un tanınıp tanınmadığını kontrol eder; MDN'nin örneklerinde at-rule(@keyframes) ve at-rule(@scope) kullanılır. named-feature() ise başka yollarla sınanamayan, önceden tanımlanmış birkaç özel özelliği sınamak için ayrılmıştır.

FonksiyonNe sınarÖrnek
selector()Seçici sözdizimiselector(:has(a, b))
font-tech()Yazı tipi teknolojisi (renkli font, OpenType özellikleri, variations vb.)font-tech(color-COLRv1)
font-format()Yazı tipi biçimifont-format(woff2)
at-rule()Bir at-rule desteklenip desteklenmediğiat-rule(@scope)
named-feature()Önceden tanımlı özel bir özelliknamed-feature(single-axis-scroll-container)
css
@supports font-tech(color-COLRv1) {
  body {
    font-family: "Bungee Spice", fantasy;
  }
}

@supports at-rule(@scope) {
  @scope (.light-scheme) {
    a {
      color: darkmagenta;
    }
  }
}

Yazı tipi biçimi için MDN önemli bir ayrıntı ekler: @supports font-format(woff2) ile iki ayrı @font-face arasında seçim yapmak mümkündür, ancak daha verimli yol tek bir @font-face kuralının src tanımında biçimleri en çok tercih edilenden en az tercih edilene doğru sıralamaktır. Tarayıcı listedeki ilk desteklediği kaynağı kullanır. @font-face ayrıntıları yazı tipi yazısında bulunuyor.

Seçici listelerinde gizli tuzak: kısmi uygulanma

selector() fonksiyonunun neden gerekli olduğunu MDN'nin @supports sayfasındaki bir örnek iyi açıklar. Normal bir seçici listesinde seçicilerden biri geçersizse kuralın tamamı atlanır. Ancak :is() gibi bazı fonksiyonlar bağışlayıcı (forgiving) seçici listesi kullanır: Anlamadıkları parçayı düşürüp kalanlarla eşleşmeye devam ederler. MDN'nin örneğinde :is(:nth-child(1n of ul, ol) a, details > summary) kuralı, :nth-child() fonksiyonunun of argümanını desteklemeyen bir tarayıcıda yalnızca details > summary parçasıyla uygulanırdı. Yani kural tamamen yok sayılmaz, yarım çalışır.

Bunu önlemek için kuralı @supports selector(:nth-child(1n of a, b)) bloğunun içine almak gerekir. Böylece of argümanını anlamayan tarayıcı bloğun tamamını atlar ve kuralın yarım hâli hiç uygulanmaz. Bu desen, bağışlayıcı seçicilerin içinde yeni sözdizimi kullandığınız her durumda işe yarar. :is() ve :where() fonksiyonlarının davranışı :has, :is, :where ve :not yazısında ayrıntılı anlatılıyor.

css
@supports selector(:nth-child(1n of a, b)) {
  /* bloğun dışında yazılsaydı, of argümanını bilmeyen tarayıcıda
     yalnızca details > summary parçası uygulanırdı */
  :is(:nth-child(1n of ul, ol) a, details > summary) {
    color: darkgreen;
  }
}

Özellik sorgusunu media query ile birleştirmek

@supports ve @media koşullu grup kurallarıdır ve birbirinin içine yerleştirilebilir. MDN'nin @media sayfasındaki sözdizimi örneğinde flex düzeni hem display: flex desteğine hem de ekranın en az 900 piksel genişliğinde olmasına bağlanır. İçteki stiller ancak iki koşul birden doğru olduğunda uygulanır. Hangi kuralı dışa, hangisini içe yazdığınızın sonuç açısından farkı yoktur; okunabilirliğe göre seçebilirsiniz.

css
@supports (display: flex) {
  @media screen and (width >= 900px) {
    article {
      display: flex;
    }
  }
}
YöntemNe zaman uygunDikkat
Yedek bildirim (aynı özelliği iki kez yazmak)Tek bir değerin yeni sürümüBirbirine bağlı birkaç kuralı birlikte yönetemez
@supports (özellik: değer)Bir grup kuralın birlikte açılıp kapanmasıYalnızca ayrıştırmayı sınar
@supports selector(...)Yeni seçici sözdizimi, bağışlayıcı listelerSeçici kuralın kendisi de geçersizse zaten atlanır
@import ... supports(...)Bütün bir stil dosyasını koşula bağlamak@import her zaman dosyanın başında olmalı

@import içinde supports() koşulu

Özellik sorgusu yalnızca @supports kuralıyla sınırlı değildir. @import kuralına supports() koşulu ekleyerek bir stil dosyasının yalnızca belirli özellikler destekleniyorsa içe aktarılmasını sağlayabilirsiniz. MDN'ye göre koşul sağlanmazsa tarayıcı dosyayı hiç getirmeyebilir; başka bir yoldan indirilmiş olsa bile yüklemez. Tek bir supports() kullanılabilir, ama içinde istediğiniz kadar koşulu not, and ve or ile birleştirebilirsiniz. Karıştırırken yine parantez zorunludur.

css
@import "grid.css" supports(display: grid) screen and (width <= 400px);
@import "flex.css" supports((not (display: grid)) and (display: flex)) screen
  and (width <= 400px);

@import "/css/webkitShadowStyles.css"
  supports(selector(::-webkit-inner-spin-button));

İlk satır grid destekleniyorsa ve ekran dar ise grid.css dosyasını, ikinci satır grid desteklenmiyor ama flex destekleniyorsa flex.css dosyasını içe aktarır. Media query listesinin supports() koşulundan sonra yazıldığına dikkat edin. @import kuralının sırası ve katmanlarla birlikte kullanımı @layer yazısında anlatılıyor.

Özellik sorgularının sınırları

MDN, özellik sorgularının neyi ölçtüğünü açıkça tanımlar: @supports, tarayıcının bir bildirimi ayrıştırıp geçerli sayıp saymadığını sınar. Bildirimi anlayan tarayıcı olumlu cevap verir. Bu, özelliğin hatasız ya da belirtime tam uygun çalıştığı anlamına gelmez; özellik sorguları kısmi uygulamaları ayırt edemez. Bir tarayıcı bir özelliği tanıyıp bazı alt durumlarını desteklemiyorsa sorgu yine doğru dönebilir.

İkinci önemli nokta, özellik sorgularının çoğu zaman zorunlu olmamasıdır. CSS'in hata işleme kuralı gereği tarayıcı tanımadığı bildirimleri sessizce yok sayar. Bu yüzden basit durumlarda aynı özelliği iki kez yazmak yeterlidir: Önce eski değer, sonra yeni değer. Yeni değeri anlamayan tarayıcı ikinci satırı atlar ve ilkini kullanır. MDN özellik sorgularını bu yedek bildirim yöntemine yararlı bir alternatif olarak sunar. Bir grup kuralın birlikte değişmesi gerektiğinde (örneğin hem düzen hem de float temizliği) sorgu daha düzenli bir çözümdür. Geçersiz bildirimlerin nasıl ele alındığı CSS hata ayıklama yazısında anlatılıyor.

css
/* yedek bildirim yöntemi: sorgu gerekmez */
.kutu {
  background-color: rgb(0 0 255);
  background-color: color-mix(in oklch, blue, white 20%);
  /* color-mix() anlaşılmazsa ikinci satır atlanır, ilki kalır */
}

Uygulamalı mini örnek: aşamalı geliştirilen galeri

Bir görsel galerisi düşünelim. Temel düzen her tarayıcıda çalışan bir flex satırı olsun; grid destekleniyorsa otomatik sütunlu bir grid düzenine geçilsin. :has() destekleniyorsa içinde görsel bulunmayan kartlara ayrıca bir stil verilsin.

css
.galeri {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.galeri > * {
  flex: 1 1 200px;
}

@supports (display: grid) {
  .galeri {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  }
}

@supports selector(:has(img)) {
  .galeri > :not(:has(img)) {
    background-color: whitesmoke;
  }
}
/* sonuç: grid anlayan tarayıcıda otomatik sütunlar;
   anlamayan tarayıcıda sarılan flex satırı;
   :has() destekleniyorsa görselsiz kartlar gri zeminli */

Grid bloğu flex düzenini tamamen değiştirmez; display değeri grid olduğunda alt öğelerdeki flex kısayolu etkisiz kalır, gap ise iki düzende de çalışır. repeat(auto-fill, minmax(200px, 1fr)) deseni auto-fill ve minmax yazısında, :has() ve :not() ise :has, :is, :where ve :not yazısında ayrıntılı anlatılıyor.

Sık yapılan hatalar

Sık yapılan hatalar: Bildirimi parantezsiz yazmak, and ile or operatörünü parantezsiz karıştırmak, Yazım hatalı değerle sınamak, Yedek stili yalnızca @supports not içine koymak
  • Bildirimi parantezsiz yazmak: @supports display: grid geçersizdir.
  • and ile or operatörünü parantezsiz karıştırmak: Koşul geçersiz olur ve tüm kural yok sayılır.
  • Yazım hatalı değerle sınamak: Geçersiz bir değer, özellik desteklense bile koşulu yanlış yapar.
  • Yedek stili yalnızca @supports not içine koymak: @supports kuralını hiç tanımayan bir tarayıcı iki bloğu da atlar. Temel stili bloğun dışında yazın.
  • Sorguyu çalışma garantisi sanmak: @supports yalnızca ayrıştırmayı sınar, kısmi ya da hatalı uygulamaları yakalamaz.
  • @import kuralını koşullu bloğun içine yazmak: @import iç içe yazılabilen bir ifade değildir; koşullu içe aktarma için supports() koşulunu @import satırına ekleyin.

Sık Sorulan Sorular

@supports ile @media arasındaki fark nedir?

MDN'ye göre ikisi de koşullu kurallar modülüne aittir ve benzer çalışır. Fark sorgulanan şeydedir: @media sayfanın çalıştığı ortamı (ekran, yazıcı, kullanıcı tercihi), @supports ise tarayıcının bir CSS özelliğini destekleyip desteklemediğini sınar.

Her yeni özellik için @supports kullanmam gerekir mi?

Gerekmez. Tarayıcı tanımadığı bildirimi yok saydığı için çoğu durumda yedek bildirim yazmak yeterlidir. Birbirine bağlı birkaç kuralı birlikte açıp kapatmanız gerektiğinde @supports kullanın.

Bir seçicinin desteklendiğini nasıl sınarım?

selector() fonksiyonunu kullanın: @supports selector(:has(a)). Seçicinin kendisini bir kuralda kullanmak da bir tür sınamadır; tarayıcı geçersiz seçiciye sahip kuralın tamamını atlar.

@supports içine @media yazabilir miyim?

Evet. İki kural da koşullu grup kuralıdır ve birbirinin içine yerleştirilebilir. İçteki stiller iki koşul birden doğruysa uygulanır.

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 · Media query sözdizimi · :has() ve :is() · @font-face ve yazı tipleri · if() ve @function · CSS hata ayıklama