Tailwind'de erişilebilirlik için hazır gelen araçlar şunlardır: ekranda görünmeyip ekran okuyucuya okunan metin için sr-only ve onu geri alan not-sr-only; yalnızca klavye odağında görünen halkalar için focus-visible:; hareketi azaltmak isteyen kullanıcılar için motion-reduce: ve motion-safe:; yüksek kontrast ve zorunlu renk modları için contrast-more: ve forced-colors:; ARIA durumlarına göre stil vermek için de aria-expanded:, aria-checked: gibi varyantlar. Bu araçların hepsi kullanıcının tercihini veya elementin gerçek durumunu CSS'e taşır; HTML'deki doğru anlam (etiket, rol, ARIA niteliği) yine sizin sorumluluğunuzdadır.

Bu yazıda her aracın v4.3.5 ile ürettiği gerçek CSS'i gösteriyor ve tipik kullanım yerlerini anlatıyoruz. Durum varyantlarının genel mantığı hover, focus ve active, ebeveyn durumuna göre stil group ve peer yazılarında; serinin tamamı Tailwind CSS öğrenme rehberi sayfasında.

sr-only: görsel olarak gizle, ekran okuyucuya bırak

sr-only: görsel olarak gizle, ekran okuyucuya bırak: hidden, invisible, sr-only, opacity-0

Yalnızca simgeden oluşan bir bağlantı veya butonun ekran okuyucu kullanıcıları için bir adı olmalıdır. hidden sınıfı burada işe yaramaz, çünkü display: none elementi erişilebilirlik ağacından da çıkarır. Belgeler sr-only'yi tam bu iş için tarif eder: element görsel olarak gizlenir ama ekran okuyucular onu okumaya devam eder.

html
<a href="#ayarlar">
  <svg aria-hidden="true">...</svg>
  <span class="sr-only">Ayarlar</span>
</a>

v4.3.5 ile derlenen CSS:

css
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border-width: 0;
}

Kural, elementi 1 piksellik bir kutuya sıkıştırıp clip-path ile kırpıyor ve position: absolute ile akıştan çıkarıyor; metin DOM'da ve erişilebilirlik ağacında kalıyor. Simgeye verdiğimiz aria-hidden="true" ise SVG'nin ayrıca okunmasını engeller. Böylece ekran okuyucu bağlantıyı yalnızca "Ayarlar" olarak duyurur.

Belgeler bir de responsive kullanım gösterir: sr-only sm:not-sr-only. Bu kombinasyonda etiket küçük ekranlarda gizli, sm ve üstünde görünür olur. Derlenen sm:not-sr-only kuralı @media (width >= 40rem) içinde gizlemeyi tek tek geri alır:

css
@media (width >= 40rem) {
  .sm\:not-sr-only {
    position: static;
    width: auto;
    height: auto;
    padding: 0;
    margin: 0;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
}
SınıfGörselEkran okuyucuYer kaplar mı
hiddengörünmezokumazhayır (display: none)
invisiblegörünmezokumazevet (visibility: hidden)
sr-onlygörünmezokurhayır (absolute, 1px)
opacity-0görünmezokurevet

Tablodaki invisible ve opacity-0 satırları display ve visibility davranışının genel CSS sonuçlarıdır; ayrıntılar display, hidden ve block yazısında. Pratik kural basit: bir metni hem gözden hem ekran okuyucudan saklamak istiyorsanız hidden, yalnızca gözden saklamak istiyorsanız sr-only kullanın. opacity-0 ile gizlenen bir buton ise hâlâ tıklanabilir ve klavyeyle odaklanabilir; bu çoğu zaman istenmeyen bir durumdur.

İçeriğe atla bağlantısı

Klavye kullanıcılarının her sayfada uzun bir menüyü sekmeyle geçmek zorunda kalmaması için sayfanın en başına bir "içeriğe atla" bağlantısı konur. Bağlantı normalde gizlidir, odaklandığında görünür. sr-only ile focus:not-sr-only birleşimi bunu yapar:

html
<a href="#icerik" class="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2">İçeriğe atla</a>
<!-- ... menü ... -->
<main id="icerik">...</main>

v4.3.5 ile derlenen CSS'in odak kısmı:

css
  .focus\:not-sr-only:focus {
    position: static;
    width: auto;
    height: auto;
    padding: 0;
    margin: 0;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
  .focus\:absolute:focus {
    position: absolute;
  }
  .focus\:top-2:focus {
    top: calc(var(--spacing) * 2);
  }
  .focus\:left-2:focus {
    left: calc(var(--spacing) * 2);
  }

focus:not-sr-only konumu static yapıyor ama hemen ardından gelen focus:absolute onu yeniden absolute yapıyor; çıktıda .focus\:absolute sonra geldiği için kazanan odur. Sonuçta bağlantı odaklandığında sol üst köşede, sayfa akışını itmeden görünür. Bu, iki sınıfın aynı özelliği ayarladığı ve sonucun CSS sırasına bağlı olduğu bir örnek; kuralın genel hâli çakışan sınıflar yazısında.

focus-visible ile görünür odak halkası

Belgelere göre focus-visible varyantı, element klavyeyle odaklandığında devreye girer; focus ise fareyle tıklama dahil her odakta çalışır. Butonlarda tıklama sonrası kalan halkayı istemiyor ama klavye kullanıcılarına net bir gösterge vermek istiyorsanız focus-visible: doğru seçimdir:

html
<button class="rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-600">Kaydet</button>
css
  .focus-visible\:outline-2:focus-visible {
    outline-style: var(--tw-outline-style);
    outline-width: 2px;
  }
  .focus-visible\:outline-offset-2:focus-visible {
    outline-offset: 2px;
  }
  .focus-visible\:outline-sky-600:focus-visible {
    outline-color: var(--color-sky-600);
  }

Outline kullanmanın bir avantajı, köşe yuvarlaklığını takip etmesi ve kutunun boyutunu değiştirmemesidir. Ring tabanlı alternatif (focus-visible:ring-2) gölge ile çizilir; ikisinin karşılaştırması shadow ve ring yazısında.

outline-none ile outline-hidden farkı

outline-none ile outline-hidden farkı

Tarayıcının varsayılan odak çizgisini kaldırırken hangi sınıfı seçtiğiniz, zorunlu renk modundaki (forced colors) kullanıcılar için fark yaratır. Belgelere göre outline-none çizgiyi tamamen kaldırır; outline-hidden ise varsayılan çizgiyi gizler ama zorunlu renk modunda korur. v4.3.5 derlemesi bu farkı açıkça gösteriyor:

html
<input class="focus:outline-hidden focus:border-sky-600">
<textarea class="outline-none"></textarea>
css
  .outline-none {
    --tw-outline-style: none;
    outline-style: none;
  }
  /* (kısaltıldı) */
  .focus\:outline-hidden:focus {
    --tw-outline-style: none;
    outline-style: none;
    @media (forced-colors: active) {
      outline: 2px solid transparent;
      outline-offset: 2px;
    }
  }

outline-hidden, zorunlu renk modu etkinken 2px'lik saydam bir outline bırakıyor. Bu modda tarayıcı renkleri sistemin paletiyle değiştirdiği için saydam çizgi görünür bir renge dönüşür ve odak kaybolmaz. Belgelerin önerisi, iki sınıftan hangisini kullanırsanız kullanın kendi odak stilinizi eklemenizdir. Not: belgelerdeki sınıf tablosu outline-hidden için outline: 2px solid transparent; outline-offset: 2px; gösteriyor; v4.3.5 çıktısı bu bildirimleri @media (forced-colors: active) içine alıyor ve normal durumda outline-style: none kullanıyor.

Hareket tercihleri: motion-reduce ve motion-safe

İşletim sisteminde hareketi azaltma ayarını açan kullanıcılar için animasyonları kapatmak ya da yumuşatmak gerekir. motion-reduce varyantı @media (prefers-reduced-motion: reduce), motion-safe varyantı ise @media (prefers-reduced-motion: no-preference) üretir. Belgelerin örneğinde dönen bir yükleme simgesi bu kullanıcılarda gizlenir:

html
<svg class="animate-spin motion-reduce:hidden">...</svg>
<button class="motion-safe:transition motion-safe:hover:-translate-y-0.5">Kaydet</button>
css
  .animate-spin {
    animation: var(--animate-spin);
  }
  /* (kısaltıldı) */
  @media (prefers-reduced-motion: no-preference) {
    .motion-safe\:transition {
      transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
      transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
      transition-duration: var(--tw-duration, var(--default-transition-duration));
    }
    @media (hover: hover) {
      .motion-safe\:hover\:-translate-y-0\.5:hover {
        --tw-translate-y: calc(var(--spacing) * -0.5);
        translate: var(--tw-translate-x) var(--tw-translate-y);
      }
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .motion-reduce\:hidden {
      display: none;
    }
  }

Belgeler iki yaklaşım arasında bir seçim önerir: önce hareketi ekleyip motion-reduce: ile tek tek geri almak çok sayıda "geri alma" sınıfı gerektirebilir; hareketi baştan motion-safe: ile yalnızca tercihi olmayan kullanıcılara vermek ise çoğu durumda daha kısa yazılır. Çıktıda iç içe medya sorgusu da dikkat çekiyor: motion-safe:hover: varyantı, hareket tercihi bloğunun içinde bir @media (hover: hover) bloğu üretti. Geçiş ve animasyon sınıfları transition ve duration ile animate sınıfları yazılarında.

Kontrast ve zorunlu renk modları

contrast-more varyantı @media (prefers-contrast: more), contrast-less varyantı @media (prefers-contrast: less) üretir. Yüksek kontrast isteyen kullanıcılar için açık gri kenarlıkları koyulaştırmak ya da soluk yardım metinlerini belirginleştirmek tipik kullanımlardır. forced-colors varyantı ise @media (forced-colors: active) üretir; bu modda tarayıcı sayfanın renklerini kullanıcının seçtiği sınırlı bir paletle değiştirir.

html
<div class="contrast-more:border-gray-500"></div>
<div class="bg-sky-500 forced-colors:border forced-colors:border-[CanvasText]"></div>
css
  @media (prefers-contrast: more) {
    .contrast-more\:border-gray-500 {
      border-color: var(--color-gray-500);
    }
  }
  @media (forced-colors: active) {
    .forced-colors\:border {
      border-style: var(--tw-border-style);
      border-width: 1px;
    }
    .forced-colors\:border-\[CanvasText\] {
      border-color: CanvasText;
    }
  }

Zorunlu renk modunda arka plan renkleri çoğu zaman kaybolur; yalnızca arka plan rengiyle ayrılan bir kutu bu modda sınırlarını yitirebilir. Örnekte bu modda bir kenarlık ekledik ve rengini keyfi değerle CanvasText sistem rengine bağladık; CLI bu değeri olduğu gibi CSS'e geçirdi. Belgeler ayrıca forced-color-adjust-none sınıfını, sınırlı paletin kullanılabilirliği bozacağı durumlar için (örneğin bir ürün renk seçicisindeki renk örnekleri) tarif eder; forced-color-adjust-auto ise bu ayarı geri alır:

html
<div class="forced-color-adjust-none lg:forced-color-adjust-auto">...</div>
css
  .forced-color-adjust-none {
    forced-color-adjust: none;
  }
  /* (kısaltıldı) */
  @media (width >= 64rem) {
    .lg\:forced-color-adjust-auto {
      forced-color-adjust: auto;
    }
  }

ARIA durumlarına göre stil

ARIA durumlarına göre stil: focus-visible, motion-reduce, motion-safe, contrast-more

Bir açılır menü butonunun aria-expanded değeri, bir sekmenin aria-selected değeri gibi ARIA nitelikleri zaten elementin durumunu söyler. Ayrı bir CSS sınıfı ekleyip çıkarmak yerine bu niteliğe göre stil vermek, görünüm ile erişilebilir durumun birbirinden kopmasını önler. Belgelere göre hazır boolean ARIA varyantları şunlardır: aria-busy, aria-checked, aria-disabled, aria-expanded, aria-hidden, aria-pressed, aria-readonly, aria-required ve aria-selected. Hepsi niteliğin "true" değerini hedefler. Başka değerler için köşeli parantezli yazım kullanılır.

html
<button aria-expanded="false" class="group">
  Menü <svg class="group-aria-expanded:rotate-180">...</svg>
</button>
<th aria-sort="ascending" class="aria-[sort=ascending]:bg-sky-50">Tarih</th>
<button aria-disabled="true" class="aria-disabled:opacity-50">Gönder</button>
css
  :is(:where(.group)[aria-expanded="true"] .group-aria-expanded\:rotate-180) {
    rotate: 180deg;
  }
  /* (kısaltıldı) */
  .aria-disabled\:opacity-50[aria-disabled="true"] {
    opacity: 50%;
  }
  .aria-\[sort\=ascending\]\:bg-sky-50[aria-sort="ascending"] {
    background-color: var(--color-sky-50);
  }

İlk kuralda group sınıflı butonun aria-expanded değeri true olduğunda içindeki ok simgesi 180 derece döner. Betiğiniz yalnızca niteliği güncellediğinde hem ekran okuyucu yeni durumu duyurur hem de görünüm değişir. aria-[sort=ascending]:bg-sky-50 kuralı tablo başlığına sıralama yönüne göre arka plan verir; aria-disabled:opacity-50 ise aria-disabled="true" taşıyan elementi soluklaştırır. Kendi ARIA varyantlarınızı @custom-variant ile tanımlayabilirsiniz; bkz. custom variant.

VaryantÜrettiği koşulTipik kullanım
focus-visible:focus-visibleKlavye odak halkası
motion-reduce@media (prefers-reduced-motion: reduce)Animasyonu kapatma
motion-safe@media (prefers-reduced-motion: no-preference)Hareketi yalnızca isteyene verme
contrast-more@media (prefers-contrast: more)Kenarlık ve metni koyulaştırma
forced-colors@media (forced-colors: active)Zorunlu renk modunda sınır ekleme
aria-expanded[aria-expanded="true"]Açılır menü oku
aria-[sort=ascending][aria-sort="ascending"]Sıralanabilir tablo başlığı

Erişilebilirlik stillerini test etmek

Bu yazıdaki sınıfların çoğu yalnızca belirli bir koşulda devreye girer; bu yüzden yazdıktan sonra o koşulu gerçekten oluşturup sonucu görmeniz gerekir. En basit test klavyedir: fareyi bırakıp sayfayı baştan sona Tab tuşuyla gezin. Her etkileşimli öğede odak göstergesini görebiliyor musunuz, "içeriğe atla" bağlantısı ilk Tab'da beliriyor mu, odak sırası görsel sırayla uyumlu mu? Bu tek test, focus-visible:, sr-only ve focus:not-sr-only kullanımlarınızın çoğunu doğrular.

Kullanıcı tercihlerine bağlı varyantlar (motion-reduce, contrast-more, forced-colors) için işletim sistemi ayarlarını değiştirmek ya da tarayıcı geliştirici araçlarındaki öykünme seçeneklerini kullanmak gerekir; Tailwind belgeleri zorunlu renk modu için bu öykünmeyi açıkça önerir. Derlenmiş CSS'e bakmak da hızlı bir ön kontroldür: bir kuralın beklediğiniz medya sorgusunun içinde olup olmadığını dosyada görebilirsiniz. ARIA varyantları için ise niteliği geliştirici araçlarında elle true yapıp stilin değişip değişmediğine bakın. Ekran okuyucuyla yapılan bir deneme, sr-only metinlerinin gerçekten okunduğunu ve simgelerin aria-hidden sayesinde atlandığını gösterir; hiçbir CSS kontrolü bu deneyimin yerini tutmaz.

Mini örnek: erişilebilir bir simge butonu

Bu yazıdaki araçların çoğunu tek bir elementte birleştiren küçük bir örnekle bitirelim: bir içeriği favorilere ekleyen, yalnızca simgeden oluşan bir aç/kapa butonu. Butonun erişilebilir adı sr-only bir metinden, durumu aria-pressed niteliğinden, odak göstergesi focus-visible: sınıflarından gelir; renk geçişi de yalnızca hareket tercihi olmayan kullanıcılara verilir:

html
<button type="button" aria-pressed="false" class="inline-flex size-10 items-center justify-center rounded-full text-gray-600 hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-600 aria-pressed:bg-sky-100 aria-pressed:text-sky-700 motion-safe:transition-colors">
  <svg class="size-5" aria-hidden="true">...</svg>
  <span class="sr-only">Favorilere ekle</span>
</button>

v4.3.5 ile derlenen CSS'in duruma bağlı kuralları:

css
/* (kısaltıldı) */
  .size-10 {
    width: calc(var(--spacing) * 10);
    height: calc(var(--spacing) * 10);
  }
  /* (kısaltıldı) */
  .aria-pressed\:bg-sky-100[aria-pressed="true"] {
    background-color: var(--color-sky-100);
  }
  .aria-pressed\:text-sky-700[aria-pressed="true"] {
    color: var(--color-sky-700);
  }
  @media (prefers-reduced-motion: no-preference) {
    .motion-safe\:transition-colors {
      transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
      transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
      transition-duration: var(--tw-duration, var(--default-transition-duration));
    }
  }
/* (kısaltıldı) */

Betik tarafında yapılması gereken tek iş, tıklamada aria-pressed değerini true ile false arasında değiştirmektir. Değer true olduğunda Tailwind'in ürettiği nitelik seçicileri devreye girer ve buton mavi tonlara geçer; ekran okuyucular da aynı niteliği okuyup butonun basılı olduğunu duyurur. Görünümü ayrı bir sınıfla değiştirseydiniz, sınıfı güncelleyip niteliği unuttuğunuz anda görsel durum ile erişilebilir durum birbirinden kopardı. size-10, 16px kökte 40px'lik bir dokunma alanı verir; simge ise size-5 ile 20px kalır ve geri kalan alan tıklanabilir boşluk olarak çalışır.

Sık yapılan hatalar

  • Simge butonlarına ad vermemek: Görünür metni olmayan her bağlantı ve butona sr-only bir etiket veya aria-label ekleyin.
  • Etiketleri hidden ile gizlemek: hidden metni ekran okuyucudan da siler; sr-only kullanın.
  • outline-none yazıp odak göstergesi eklememek: Klavye kullanıcıları odağı kaybeder.
  • Hareketi her kullanıcıya zorlamak: Büyük kaydırma veya zıplama efektlerini motion-safe: ile sınırlayın.
  • Durumu yalnızca sınıfla göstermek: Açık/kapalı durumunu bir CSS sınıfıyla değil ARIA niteliğiyle tutup aria-* varyantlarıyla stilleyin.
  • Bilgiyi yalnızca renkle vermek: Zorunlu renk modunda renkler değişir; hata durumunu metin veya simgeyle de belirtin.

Sık Sorulan Sorular

sr-only ile aria-label arasında hangisini seçmeliyim?

İkisi de erişilebilir bir ad verir. sr-only metni DOM'da tuttuğu için çeviri araçları ve arama işlevleri tarafından da görülür ve sm:not-sr-only gibi responsive geçişlere izin verir. Tailwind tarafında bunun için yalnızca sr-only sınıfı vardır; aria-label bir HTML niteliğidir.

hover stilleri dokunmatik cihazlarda neden çalışmıyor?

v4'te hover: varyantı @media (hover: hover) içinde üretilir; birincil girişi üzerine gelmeyi desteklemeyen cihazlarda uygulanmaz. Bu yüzden önemli bir bilgiyi yalnızca hover durumunda göstermeyin; ayrıntılar sık hatalar yazısında.

İçeriğe atla bağlantısı neden focus:absolute ile birlikte yazılıyor?

focus:not-sr-only tek başına elementi position: static yapar ve bağlantı belgenin akışına girerek odaklandığı anda sayfanın üst kısmını aşağı iter. focus:absolute focus:top-2 focus:left-2 eklendiğinde bağlantı akıştan çıkar ve köşede belirir; sayfa düzeni kıpırdamaz. Bağlantıya ayrıca zemin rengi ve iç boşluk vermek, onu odaklandığında okunur kılar.

Tailwind erişilebilirliği otomatik sağlar mı?

Hayır. Tailwind, kullanıcı tercihlerini ve element durumlarını CSS'e taşıyan varyantlar sunar; doğru HTML elementlerini seçmek, etiket ve ARIA niteliklerini eklemek, renk kontrastını kontrol etmek geliştiricinin işidir.

Yazdırma için ayrı stil verebilir miyim?

Evet, belgelerin hızlı başvuru tablosunda print varyantı @media print olarak geçer. Örneğin menüyü yazdırmada gizlemek için print:hidden yazılabilir.

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: Tailwind CSS öğrenme rehberi · Hover ve focus durumları · Group ve peer · Form stilleri · Transition ve duration · Display sınıfları