Erişilebilirlik (A11y) Kontrolleri
Semantik HTML kullan; <div> yığınlarına son
Ekran okuyucular ve arama motorları sayfa yapısını etiket anlamından çıkarır. <button> yerine <div onclick> kullandığında klavye, enter, rol, focus — hepsini kendin kurmak zorunda kalırsın ve genelde unutulur.
<header>, <nav>, <main>, <article>, <aside>, <footer>. Tıklanabilir → <button> veya <a>. Form kontrolleri → <label>, <fieldset>, <legend>. Liste → <ul>/<ol>/<li>.
Yanlış: <div class="btn" onclick=...>Gönder</div>. Doğru: <button type="submit">Gönder</button>.
Görsellere anlamlı alt metin yaz
Ekran okuyucu kullanıcıları, görme engelliler ve görseli yüklenmeyen herkes alt metne bağımlıdır. Eksik alt = içeriğin bir kısmı kayıp.
Bilgi taşıyan görsellerde alt içeriği anlat, estetik/dekoratif olanlarda alt="". Aynı sayfada ikon + metin varsa, ikon aria-hidden="true". Anahtar kelime sıkıştırma değil, faydalı açıklama yaz.
Yanlış: <img src="logo.png" alt="logo">. Doğru: <img src="logo.png" alt="Duck — Fikirden mimariye proje sihirbazı"> veya dekoratifse alt="".
Renk kontrastı en az 4.5:1 (küçük metin)
Düşük kontrast, görme yeteneği azalmış kullanıcılar ve güneşli ortamda telefon kullananlar için okunamaz. WCAG AA minimum normal metin 4.5:1, büyük metin 3:1.
Tasarım aşamasında renk paletini kontrast için test et (Figma Contrast, contrast-ratio.com). Gri üzeri açık gri tipografi kaçın. Placeholder metni değeri göstermek için kullanma; #999 kontrast geçmez.
Bootstrap 5: text-muted varsayılan #6c757d (bg-white üstünde 4.54:1 — AA geçer). Daha açık rengi AA kaybeder.
Görünür focus göstergesi bırak
Klavye, ekran okuyucu ve Switch kullanıcıları nerede olduğunu focus ring'den görür. 'outline: none' koymak en sık yapılan a11y hatasıdır.
Global outline'ı kaldırma. Özel tasarım istiyorsan :focus-visible ile ring'i yeniden tanımla (kontrast yeterli, kalınlık ≥2px). Fare kullanıcısı için dikkat dağıtmasını istemiyorsan :focus-visible sadece klavyede çalışır.
button:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; } Tüm etkileşim klavyeyle çalışsın
Trackpad/fare kullanamayan herkes klavyeye dayanır. Sadece hover'da ortaya çıkan menü, sadece drag ile taşınan kart — herkes için engel.
Tab sırası doğal olmalı. Modal'da focus-trap kur, kapanınca focus'u tetikleyene döndür. Dropdown'lar arrow key + enter ile çalışsın. Escape modal/dropdown'u kapatsın. Drag işlemlerine klavye alternatifi koy.
dnd-kit: klavye sensor'ünü etkinleştir → space ile 'tut', arrow ile taşı, space ile 'bırak'.
Form kontrollerinin her zaman etiketi olsun
Placeholder kaybolur ve etiket yerine geçmez. Label'siz alanda ekran okuyucu 'text field' der ve kullanıcı ne girdiğini bilmez.
<label for="id">...</label> + <input id="id"> veya label içine wrap et. İkon-buton için aria-label. Grup (ör. radio) için <fieldset>/<legend>. Zorunluluğu aria-required ile belirt.
<label for="email">E-posta</label><input id="email" type="email" required aria-required="true">
ARIA'yı sadece gerekliyse kullan — doğal HTML önceliği
'No ARIA is better than bad ARIA.' Yanlış role/state kullanımı erişilebilirliği doğrudan bozar. Çoğu ihtiyaç zaten HTML etiketleriyle karşılanır.
role="button" yerine <button>. Özel pattern'lar (combobox, tablist, tree) için WAI-ARIA Authoring Practices'e uy. Dinamik içeriğe aria-live="polite"/"assertive".
Toast bildirimi: <div role="status" aria-live="polite"> içerik </div> ekran okuyucu tarafından okunur.
Skip link ekle — klavye kullanıcısı menüyü atlayabilsin
Her sayfada aynı 20-50 menü öğesini tab'layarak geçmek yorucudur. Skip link ana içeriğe tek atlayış verir.
Sayfanın ilk odaklanabilir elemanı 'İçeriğe atla' linki olsun. Normalde görünmez, focus aldığında görünür.
<a class="visually-hidden-focusable" href="#main">İçeriğe atla</a> + <main id="main">…</main>
Sadece renge güvenme — durumu ek işaretle belirt
Renk körü kullanıcılar kırmızı/yeşil farkı göremez. Durum sadece renkle anlatılırsa bu kullanıcılar için bilgi yok demektir.
Hata rengine ek olarak ikon + metin. Zorunlu alana (*) ekle, sadece kırmızı kenarlık yeterli değil. Chart'larda desen/shape variasyonu koy.
Form: kırmızı kenarlık + ⚠ ikonu + 'Geçersiz e-posta' metni. Chart: çizgiler sadece renkle değil, dash/dot pattern ile de ayırt.
Hareket azaltma tercihine saygı göster
Vestibüler hassasiyeti olan kullanıcılar için agresif parallax/animasyon baş dönmesi yapar. OS'teki 'reduce motion' tercihini takip etmezsen sitenin içinde kalamazlar.
prefers-reduced-motion: reduce media query'si ile animasyonları kısa ya da kapalı yap. Auto-playing video için opt-in iste.
@media (prefers-reduced-motion: reduce) { * { animation-duration: .01ms !important; transition-duration: .01ms !important; } } Sayfanın ve bölümlerin dilini belirt
Ekran okuyucu doğru sesleri üretmek için dili bilmek zorundadır. Yanlış lang → İngilizce okunuşla Türkçe metin = kullanıcı için karmaşa.
<html lang="tr"> veya kullanıcının dilini yansıtacak şekilde dinamik. Farklı dilde bir alıntı varsa span lang="en" ile işaretle.
Duck Layout'ta <html lang="@L.CurrentCode"> → TR/EN arası geçince doğru ses.
Medyaya altyazı ve transkript ekle
Sessiz ortamda veya işitme engelli izleyiciler için altyazı şart. Transkript ise arama motoru ve içeriği hızlıca tarayanlar için değerli.
Video için WebVTT subtitle dosyası (<track kind="captions">). Podcast için metin transkript yayımla. Otomatik üretim (Whisper) kabul edilebilir ama gözden geçir.
<video><track kind="captions" src="subs.tr.vtt" srclang="tr" label="Türkçe" default></video>