ERETEK
BİLGİ SİSTEMLERİ

WCAG 2.2 ile Web Uygulamasında Erişilebilirlik: Geliştirici Rehberi

WCAG 2.2 ölçütlerini koda çevirin: semantik HTML, ARIA, klavye ve odak yönetimi, form hataları, kontrast, axe ile CI testi ve bileşen bazlı kontrol listesi.

Bu makalede7 bölüm
Teknik özet
Teknoloji
WCAG 2.2, WAI-ARIA, HTML, CSS, axe-core, Playwright, NVDA, VoiceOver
Konu
Web uygulamasında WCAG 2.2 AA ölçütlerini kodda uygulamak
Seviye
Orta
Ön koşullar
  • HTML ve CSS temel bilgisi
  • Bir bileşen tabanlı ön yüz çatısıyla çalışma deneyimi

Klavyeyle açılmayan bir menü, etiketsiz bir form alanı, div ile yapılmış bir “düğme”: tek başına küçük hatalar. Sorun, bunların bileşen kütüphanesinden onlarca ekrana kopyalanmış olarak yayın öncesi denetim raporunda ortaya çıkmasıdır. O noktada düzeltme pahalıdır. Bu rehber WCAG 2.2 başarı ölçütlerini ön yüz geliştiricisinin günlük kararlarına çevirir: semantik HTML, ARIA, klavye ve odak, formlar, kontrast ve test akışı, bileşen düzeyinde.

WCAG yapısı ve uygunluk seviyeleri

WCAG (Web Content Accessibility Guidelines) W3C tarafından yayımlanır ve dört ilkeye dayanır: algılanabilir, işletilebilir, anlaşılabilir ve sağlam (POUR). Her ilkenin altında yönergeler, yönergelerin altında test edilebilir başarı ölçütleri vardır. Her ölçüt A, AA veya AAA seviyesindedir; kurumsal web projelerinde ve mevzuat atıflarında hedef genellikle AA’dır, yani A ve AA ölçütlerinin tamamı.

WCAG 2.2, 2.1’in üzerine yeni ölçütler ekledi ve 4.1.1 Parsing ölçütünü kaldırdı. Geliştiriciyi doğrudan ilgilendiren yeni ölçütler şunlar:

Ölçüt Seviye Kodda karşılığı
2.4.11 Focus Not Obscured (Minimum) AA Yapışkan başlık/çerez bandı odaklanan öğeyi tamamen örtmemeli
2.5.7 Dragging Movements AA Sürükle-bırak işlemlerinin tek işaretçi alternatifi olmalı
2.5.8 Target Size (Minimum) AA Tıklama hedefleri en az 24×24 CSS piksel veya yeterli aralıklı
3.2.6 Consistent Help A Yardım bağlantısı sayfalarda aynı göreli konumda
3.3.7 Redundant Entry A Aynı süreçte girilmiş bilgi tekrar istenmemeli ya da otomatik doldurulmalı
3.3.8 Accessible Authentication (Minimum) AA Girişte bilişsel test zorunlu olmamalı; parola yöneticisi ve yapıştırma engellenmemeli

Ölçütlerin tam metni ve “Understanding” belgeleri için birincil kaynak W3C WCAG 2.2 Recommendation sayfasıdır. Bir ölçütü yorumlarken blog yazısına değil, bu belgelerdeki örnek ve istisnalara bakın. Tartışma orada biter.

Semantik HTML ve ARIA kullanımı

Erişilebilirlik hatalarının büyük kısmı doğru HTML öğesiyle çözülür. <button> klavyeyle odaklanır, Enter ve Space ile tetiklenir, ekran okuyucuya “düğme” olarak bildirilir. Aynı davranışı <div onclick> ile elde etmek için tabindex, role ve klavye olay işleyicileri eklemek gerekir; kod incelemesinde bunlardan en az birinin eksik olduğunu sık görürüz. 1.3.1 Info and Relationships ve 4.1.2 Name, Role, Value ölçütleri bu hataların doğrudan karşılığıdır.

  • Sayfa bölgeleri için header, nav, main, footer kullanın; ekran okuyucu kullanıcıları bu bölgeler arasında atlar.
  • Başlık seviyesini görsel boyuta göre değil, içerik hiyerarşisine göre seçin; görünümü CSS ayarlar.
  • Gezinme için <a href>, eylem için <button>. Sayfa değiştiren bir “düğme” ya da işlem yapan bir “bağlantı” kullanıcı beklentisini bozar.
  • Tablo verisini <table> ile, başlık hücrelerini <th scope> ile işaretleyin.

ARIA’nın ilk kuralı: eşdeğer bir yerel HTML öğesi varsa ARIA kullanmayın. ARIA yalnız erişilebilirlik ağacındaki bilgiyi değiştirir, davranış eklemez. role="button" verilen bir öğe hâlâ klavyeyle tetiklenmez. Rol bir etikettir, motor değil. ARIA’nın gerçekten gerektiği yer HTML’de karşılığı olmayan bileşenlerdir: sekmeler, birleşik kutu (combobox), ağaç görünümü, menü düğmesi. Bu desenlerin beklenen rol, durum ve klavye davranışları W3C ARIA Authoring Practices Guide içinde tanımlıdır; özel bileşen yazarken bu desenden sapmayın.

<!-- Yanlış: ikon düğmenin erişilebilir adı yok -->
<button><svg>…</svg></button>

<!-- Doğru: görünmez ad + dekoratif ikon -->
<button aria-label="Filtreleri temizle">
  <svg aria-hidden="true" focusable="false">…</svg>
</button>

<!-- Açılır panel: durum ARIA ile bildirilir -->
<button aria-expanded="false" aria-controls="filtre-paneli">Filtreler</button>
<div id="filtre-paneli" hidden>…</div>

Klavye erişimi ve odak yönetimi

2.1.1 Keyboard tüm işlevlerin klavyeyle kullanılabilmesini, 2.1.2 No Keyboard Trap odağın bir bileşene girdikten sonra orada hapsolmamasını ister. 2.4.3 Focus Order sıranın anlamlı, 2.4.7 Focus Visible odağın görünür olmasını şart koşar. Kodda karşılığı şudur:

  • Pozitif tabindex değerleri (1, 2, 3…) kullanmayın; odak sırasını DOM sırası belirler. Görsel sıra CSS ile DOM sırasından ayrılmışsa (ör. order, flex-direction: row-reverse) odak kullanıcıya rastgele zıplıyor gibi görünür.
  • outline: none ile odak halkasını kaldırdıysanız :focus-visible ile belirgin bir alternatif tanımlayın. Sahada en sık bulduğumuz hata, bir CSS reset dosyasının odak halkasını sessizce silmesidir.
  • Modal açılınca odağı içeri taşıyın, açıkken arka plana kaçmasını engelleyin, Escape ile kapatın, kapanınca odağı modalı açan düğmeye geri verin. Yerel <dialog> öğesinin showModal() yöntemi arka planı etkisiz (inert) yapar ve Escape davranışını sağlar.
  • Tek sayfa uygulamalarında rota değişince odak eski sayfadaki tıklanan bağlantıda kalır. Yeni sayfanın ana başlığına (tabindex="-1" ile) odak taşıyın ve document.title’ı güncelleyin.
  • Uzun gezinme menülerinden önce “İçeriğe geç” bağlantısı koyun (2.4.1 Bypass Blocks).
/* Odak görünürlüğü: yalnız klavye odağında belirgin halka */
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

/* Yapışkan başlık odaklanan öğeyi örtmesin (2.4.11) */
html { scroll-padding-top: 5rem; }

Formlar, hata mesajları ve dinamik içerik

Özel web uygulamalarında erişilebilirlik hatalarının en yoğun olduğu yer formlardır. Her alanın programatik olarak bağlı bir etiketi olmalı (<label for>). placeholder etiketin yerini tutmaz: yazmaya başlayınca kaybolur, kontrastı da genellikle düşüktür. İlgili alanlar (adres bloğu, radyo grubu) <fieldset> ve <legend> ile gruplanır.

Hata tarafında 3.3.1 Error Identification hatanın metinle belirtilmesini, 3.3.3 Error Suggestion mümkünse düzeltme önerisi verilmesini ister. Yalnız kırmızı kenarlık yetmez (1.4.1 Use of Color). Renk körü kullanıcı hangi alanın hatalı olduğunu göremez.

<label for="vergi-no">Vergi numarası</label>
<input id="vergi-no" name="vergiNo" inputmode="numeric"
       autocomplete="off"
       aria-invalid="true"
       aria-describedby="vergi-no-ipucu vergi-no-hata">
<p id="vergi-no-ipucu">10 haneli vergi numaranızı girin.</p>
<p id="vergi-no-hata">Vergi numarası 10 haneden oluşmalıdır.</p>

Gönderimde birden fazla hata varsa formun başına bir hata özeti koyup odağı oraya taşıyın, özetteki her maddeyi ilgili alana bağlayın. Doğrulama kurallarını istemci ve sunucuda tutarlı kurmak ve sunucu hatalarını alanlara eşlemek form doğrulamasını tek şemayla yönetmek rehberinde ele alınıyor.

Sayfa yenilenmeden değişen içerikler (“Kaydedildi”, “3 sonuç bulundu”, arka plan işleminin bitmesi) 4.1.3 Status Messages kapsamındadır. Bu mesajlar odak taşınmadan bildirilir: role="status" (kibar, sıradaki fırsatta okunur) veya acil hatalar için role="alert". Canlı bölge öğesi, içerik değişmeden önce DOM’da bulunmalıdır. Mesajla aynı anda DOM’a eklenen bir canlı bölge birçok ekran okuyucu–tarayıcı kombinasyonunda güvenilir biçimde duyurulmaz; “bizde çalışıyor” deyip NVDA’da sessiz kalan bildirimlerin nedeni çoğu zaman budur.

Kontrast, hareket ve görsel düzen

Konu Ölçüt Eşik
Normal metin kontrastı 1.4.3 (AA) En az 4,5:1
Büyük metin kontrastı 1.4.3 (AA) En az 3:1 (18 pt veya 14 pt kalın)
Arayüz bileşeni ve grafik kontrastı 1.4.11 (AA) En az 3:1
Yeniden akış 1.4.10 (AA) 320 CSS piksel genişlikte yatay kaydırma olmadan
Metin boyutlandırma 1.4.4 (AA) %200 yakınlaştırmada işlev kaybı yok

Kontrastı her ekranda tek tek ölçmeyin; tasarım token’ları düzeyinde doğrulayın ve onaylı renk çiftlerinin listesini tutun. Bu yaklaşım kurumsal tasarım sistemi rehberinde token yönetimiyle birlikte anlatılıyor. Devre dışı (disabled) bileşenler kontrast ölçütünden muaftır; ama kullanıcı neden devre dışı olduğunu anlayamıyorsa bu yine bir kullanılabilirlik sorunudur.

Paralaks, otomatik dönen karuseller ve büyük geçiş animasyonları vestibüler rahatsızlığı olan kullanıcıları etkiler. 2.2.2 Pause, Stop, Hide (A), kendiliğinden başlayan, beş saniyeden uzun süren ve başka içerikle birlikte sunulan hareketin duraklatılabilmesini, durdurulabilmesini veya gizlenebilmesini ister. İşletim sistemindeki “hareketi azalt” tercihine uymak birkaç satırlık iştir; aşağıdaki örnek bunu genel bir kuralla yapar:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Test yöntemi ve bileşen kontrol listesi

Otomatik araçlar (axe-core, Lighthouse erişilebilirlik denetimi, WAVE) eksik alt metni, düşük kontrastı, etiketsiz alanı ve geçersiz ARIA özniteliğini hızla yakalar. Odak sırasının mantıklı olup olmadığını, alt metnin bir şey anlatıp anlatmadığını, modalın klavyeyle kullanılıp kullanılamadığını ise değerlendiremez. Yeşil rapor, erişilebilir uygulama demek değildir. Test akışını bu yüzden üç katmanda kurun:

  1. Geliştirme ve CI: Bileşen testlerinde jest-axe veya Playwright ile @axe-core/playwright kullanarak her bileşen ve kritik sayfa için otomatik tarama yapın; yeni ihlal çıkarsa derleme kırılsın.
  2. Klavye testi: Fareyi kenara çekin. Tab, Shift+Tab, Enter, Space, Escape ve ok tuşlarıyla her iş akışını baştan sona tamamlayın. Odak her an görünür, sıra mantıklı olmalı.
  3. Ekran okuyucu testi: Windows’ta NVDA, macOS ve iOS’ta VoiceOver, Android’de TalkBack ile kritik akışları dinleyin. Her bileşenin adı, rolü ve durumu doğru okunmalı, durum mesajları duyurulmalı.
// Playwright + axe ile sayfa taraması
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test('sipariş listesi WCAG AA ihlali içermez', async ({ page }) => {
  await page.goto('/siparisler');
  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
    .analyze();
  expect(results.violations).toEqual([]);
});

Bileşen kontrol listesi

  • Düğme: Yerel <button>; ikon düğmelerde erişilebilir ad; hedef boyutu en az 24×24 CSS piksel.
  • Modal: Açılınca odak içeride, Escape ile kapanır, kapanınca odak geri döner, başlığı aria-labelledby ile bağlı.
  • Açılır menü / combobox: APG desenine uygun ok tuşu davranışı, aria-expanded güncel, seçili seçenek bildiriliyor.
  • Form alanı: Görünür etiket, ipucu ve hata aria-describedby ile bağlı, hata metinle ifade ediliyor, autocomplete doğru değerde.
  • Tablo: Başlık hücreleri th ve scope ile; sıralanabilir sütunda aria-sort.
  • Bildirim: Önceden DOM’da bulunan role="status" bölgesi; kendiliğinden kaybolan bildirimlerde yeterli süre veya kalıcı alternatif.
  • Görsel: Anlam taşıyan görselde açıklayıcı alt, dekoratif görselde boş alt="".

Erişilebilirliği bileşen kütüphanesi düzeyinde çözerseniz aynı hata her ekranda yeniden yapılmaz; düzeltme bir kez yapılır, her yere dağılır. Tasarım sistemiyle birlikte erişilebilir bileşen seti kurmak için UI/UX ve kurumsal tasarım sistemi hizmet sayfasına bakabilirsiniz.

Sık sorulan sorular

Kurumsal bir web uygulaması için hangi WCAG seviyesi hedeflenmeli?

Yaygın hedef WCAG 2.2 AA seviyesidir; A ve AA seviyesindeki tüm başarı ölçütlerinin karşılanması demektir. AAA ölçütlerinin tamamı her içeriğe uygulanabilir olmadığından genellikle yalnız seçili ölçütler hedeflenir.

Otomatik erişilebilirlik araçları yeterli mi?

Hayır. axe-core veya Lighthouse kontrast, eksik etiket ve geçersiz ARIA gibi makinenin ölçebildiği hataları bulur. Odak sırasının mantığı, alt metnin anlamlılığı ve karmaşık bileşenlerin kullanılabilirliği klavye ve ekran okuyucuyla manuel test ister.

ARIA eklemek erişilebilirliği her zaman artırır mı?

Hayır. ARIA yalnız yardımcı teknolojiye iletilen bilgiyi değiştirir, davranış eklemez. Yanlış rol veya eksik klavye desteğiyle eklenen ARIA, hiç ARIA olmamasından kötü sonuç verebilir. Önce yerel HTML öğesini kullanın.

WCAG 2.2’ye geçerken en çok hangi alanlar etkilenir?

En sık etkilenen alanlar küçük tıklama hedefleri, yapışkan başlıkların odaklanan öğeyi örtmesi, sürükle-bırakla çalışan arayüzler ve parola yapıştırmayı engelleyen ya da bilişsel test isteyen giriş ekranlarıdır.

Teknik özet
Teknoloji
WCAG 2.2, WAI-ARIA, HTML, CSS, axe-core, Playwright, NVDA, VoiceOver
Konu
Web uygulamasında WCAG 2.2 AA ölçütlerini kodda uygulamak
Seviye
Orta
Ön koşullar
  • HTML ve CSS temel bilgisi
  • Bir bileşen tabanlı ön yüz çatısıyla çalışma deneyimi
Eretek uzman desteği

Bu konu sizin ortamınızda nasıl çalışır, birlikte bakalım.

Mevcut yapınızı inceliyor, darboğazı tespit ediyor ve uygulanabilir bir iş planı öneriyoruz.