Web Accessibility 2025: WCAG 2.2 Compliance ve Inclusive Design Best Practices
2025'te web accessibility artık yasal zorunluluk. WCAG 2.2 Level AA standartlarını karşılayan, herkes için erişilebilir web siteleri nasıl oluşturulur? Semantic HTML, ARIA, keyboard navigation ve screen reader optimization rehberi.
Web Accessibility 2025: WCAG 2.2 Compliance ve Inclusive Design Best Practices
2025'te web accessibility artık "nice to have" değil, legal requirement. Avrupa Birliği'nin European Accessibility Act (Haziran 2025), Amerika'nın ADA Title III, ve Türkiye'nin Erişilebilirlik İzleme ve Denetleme Yönetmeliği web sitelerini erişilebilir olmaya zorluyor. Compliance deadline'ları yaklaşırken, WCAG 2.2 Level AA standart minimum oldu.
Ancak erişilebilirlik sadece yasal zorunluluktan ibaret değil. Dünya nüfusunun %15'i (~1 milyar kişi) engelli. Erişilebilir site, daha geniş kitleye ulaşmak, SEO iyileştirmek ve kullanıcı deneyimini herkes için iyileştirmek demek.
Bu kapsamlı rehberde, WCAG 2.2 standartlarını, Perceivable-Operable-Understandable-Robust (POUR) prensiplerini, ve modern accessibility implementation techniques'lerini detaylı inceleyeceğiz.
İçindekiler
- WCAG 2.2 Nedir?
- POUR Prensipleri
- Semantic HTML ile Foundation
- ARIA: When ve How
- Keyboard Navigation
- Screen Reader Optimization
- Color Contrast ve Visual Design
- Forms ve Input Accessibility
- Testing ve Auditing
- Sık Sorulan Sorular
WCAG 2.2 Nedir?
Web Content Accessibility Guidelines (WCAG) 2.2, W3C tarafından Ekim 2023'te yayınlanan en güncel erişilebilirlik standardıdır. WCAG 2.1'e 9 yeni success criteria ekledi.
Compliance Levels
Level A: Minimum accessibility (temel) Level AA: Recommended standard (çoğu yasal gereklilik) Level AAA: En yüksek seviye (specialized content)
Çoğu yasal gereklilik Level AA compliance'ı hedefler.
WCAG 2.2'de Yeni Gelen Success Criteria
-
2.4.11 Focus Appearance (Enhanced) - AA
- Focus indicator en az 2 CSS pixel kalınlığında
- Unfocused state ile %3 contrast farkı
-
2.4.12 Focus Not Obscured (Minimum) - AA
- Focused element partially görünür olmalı
- Sticky header/footer focus'u tamamen örtmemeli
-
2.4.13 Focus Not Obscured (Enhanced) - AAA
- Focused element fully görünür olmalı
-
2.5.7 Dragging Movements - AA
- Drag&drop'a single-pointer alternative olmalı
- Mobil ve motor skill issues için kritik
-
2.5.8 Target Size (Minimum) - AA
- Touch target minimum 24x24 CSS pixels
- Önceki 2.5.5'te 44x44'tü (AAA), şimdi 24x24 AA seviye
-
3.2.6 Consistent Help - A
- Help mechanism tutarlı pozisyonda olmalı
-
3.3.7 Redundant Entry - A
- Aynı session'da tekrar bilgi girişi gerektirme
- Autofill/autocomplete kullan
-
3.3.8 Accessible Authentication (Minimum) - AA
- Cognitive function test gerektirmeyen authentication
- CAPTCHA alternative'leri
-
3.3.9 Accessible Authentication (Enhanced) - AAA
- Hiçbir cognitive function test yok
POUR Prensipleri
WCAG'ın foundation'ı dört prensip: Perceivable, Operable, Understandable, Robust.
1. Perceivable - Algılanabilir
İçerik kullanıcıların algılayabileceği formatta sunulmalı.
<!-- ❌ Kötü - Görsel bilgi alt text yok -->
<img src="chart.png" />
<!-- ✅ İyi - Descriptive alt text -->
<img
src="chart.png"
alt="Satış grafiği: 2024'te %35 artış gösteriyor, Q1'de $50k'dan Q4'te $67k'ya yükseliş"
/>
<!-- ❌ Kötü - Renk ile convey edilen info -->
<p style="color: red;">Hata oluştu</p>
<!-- ✅ İyi - Renk + icon + text -->
<p role="alert">
<span aria-hidden="true">⚠️</span>
<strong>Hata:</strong> Form gönderilemedi
</p>2. Operable - İşletilebilir
UI componentleri ve navigation işletilebilir olmalı.
<!-- ❌ Kötü - Sadece mouse ile çalışır -->
<div onclick="submit()">Gönder</div>
<!-- ✅ İyi - Keyboard accessible -->
<button type="submit">Gönder</button>
<!-- ❌ Kötü - Timeout with no control -->
<div>Session 60 saniyede sona erecek</div>
<!-- ✅ İyi - Uzatma seçeneği -->
<div role="alert">
Session 60 saniyede sona erecek.
<button onclick="extendSession()">Uzat</button>
</div>3. Understandable - Anlaşılabilir
İçerik ve UI operation anlaşılır olmalı.
<!-- ❌ Kötü - Belirsiz link text -->
<a href="/products">Buraya tıklayın</a>
<!-- ✅ İyi - Descriptive link text -->
<a href="/products">Ürün kataloğunu görüntüle</a>
<!-- ❌ Kötü - Error without explanation -->
<input type="email" required />
<span>Geçersiz</span>
<!-- ✅ İyi - Clear error message -->
<label for="email">Email:</label>
<input
type="email"
id="email"
required
aria-describedby="email-error"
/>
<span id="email-error" role="alert">
Lütfen geçerli bir email adresi girin (örnek: ali@example.com)
</span>4. Robust - Sağlam
İçerik assistive technologies ile çalışmalı.
<!-- ❌ Kötü - Custom div button -->
<div class="button" onclick="submit()">Gönder</div>
<!-- ✅ İyi - Proper semantic element -->
<button type="submit">Gönder</button>
<!-- ❌ Kötü - Invalid ARIA -->
<div role="button" aria-label="Gönder" aria-pressed="maybe">
Gönder
</div>
<!-- ✅ İyi - Valid ARIA usage -->
<button type="button" aria-pressed="false">
Toggle
</button>Semantic HTML ile Foundation
Accessibility'nin %80'i doğru HTML kullanmakla başlar.
Heading Hierarchy
<!-- ❌ Kötü - Heading order broken -->
<h1>Ana Başlık</h1>
<h3>Alt Başlık</h3> <!-- h2 atlandı! -->
<!-- ✅ İyi - Proper hierarchy -->
<h1>Ana Başlık</h1>
<h2>Alt Başlık</h2>
<h3>Detay Başlık</h3>Screen reader kullanıcıları heading'lere göre navigate eder. Broken hierarchy navigation'ı bozar.
Landmark Regions
<!-- ✅ Semantic HTML landmarks -->
<header>
<nav aria-label="Ana navigasyon">
<ul>
<li><a href="/">Ana Sayfa</a></li>
<li><a href="/about">Hakkında</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>Blog Yazısı</h1>
<p>İçerik...</p>
</article>
<aside aria-label="İlgili yazılar">
<h2>İlgili İçerikler</h2>
</aside>
</main>
<footer>
<p>© 2025 Company</p>
</footer>Screen reader'lar otomatik olarak landmark'ları detect eder ve navigation shortcuts sağlar.
Lists ve Tables
<!-- ✅ Proper list semantics -->
<ul>
<li>Öğe 1</li>
<li>Öğe 2</li>
</ul>
<!-- ✅ Table with headers -->
<table>
<caption>2024 Satış Raporu</caption>
<thead>
<tr>
<th scope="col">Ay</th>
<th scope="col">Satış</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Ocak</th>
<td>$50,000</td>
</tr>
</tbody>
</table>ARIA: When ve How
Rule #1: No ARIA is better than bad ARIA.
ARIA (Accessible Rich Internet Applications), HTML'in yetersiz kaldığı yerlerde kullanılır.
ARIA Kullanım Prensipleri
<!-- ❌ Gereksiz ARIA -->
<button role="button" aria-label="Gönder">Gönder</button>
<!-- Button zaten button, label zaten var -->
<!-- ✅ Semantic HTML yeterli -->
<button>Gönder</button>
<!-- ✅ ARIA gerekli - Custom widget -->
<div
role="tablist"
aria-label="Account settings"
>
<button
role="tab"
aria-selected="true"
aria-controls="profile-panel"
id="profile-tab"
>
Profil
</button>
<button
role="tab"
aria-selected="false"
aria-controls="security-panel"
id="security-tab"
>
Güvenlik
</button>
</div>
<div
role="tabpanel"
id="profile-panel"
aria-labelledby="profile-tab"
>
Profil içeriği
</div>Common ARIA Patterns
Modal Dialog:
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-desc"
>
<h2 id="dialog-title">Silme Onayı</h2>
<p id="dialog-desc">Bu işlem geri alınamaz.</p>
<button onclick="confirmDelete()">Sil</button>
<button onclick="closeDialog()">İptal</button>
</div>Alert/Notification:
<!-- Anında announce edilir -->
<div role="alert">
Form başarıyla gönderildi!
</div>
<!-- Live region - Updates announce edilir -->
<div aria-live="polite" aria-atomic="true">
<p>Sepetinizde <span id="cart-count">3</span> ürün var</p>
</div>Combobox/Autocomplete:
<label for="search">Arama:</label>
<input
type="text"
id="search"
role="combobox"
aria-expanded="false"
aria-controls="suggestions"
aria-autocomplete="list"
/>
<ul id="suggestions" role="listbox">
<li role="option" aria-selected="false">Sonuç 1</li>
<li role="option" aria-selected="false">Sonuç 2</li>
</ul>Keyboard Navigation
%15-20 web kullanıcısı keyboard-only navigation yapıyor (motor disabilities, power users, vb.).
Keyboard Essentials
/* ❌ Kötü - Focus outline kaldırılmış */
*:focus {
outline: none;
}
/* ✅ İyi - Visible focus indicator */
:focus {
outline: 3px solid #4A90E2;
outline-offset: 2px;
}
/* ✅ Daha iyi - Mouse click için outline yok, keyboard için var */
:focus:not(:focus-visible) {
outline: none;
}
:focus-visible {
outline: 3px solid #4A90E2;
outline-offset: 2px;
}Tab Order Management
<!-- ✅ Natural tab order -->
<form>
<input type="text" name="name" />
<input type="email" name="email" />
<button type="submit">Gönder</button>
</form>
<!-- ❌ Kötü - Positive tabindex (avoid!) -->
<button tabindex="3">Three</button>
<button tabindex="1">One</button>
<button tabindex="2">Two</button>
<!-- ✅ İyi - tabindex -1 for programmatic focus -->
<div tabindex="-1" id="error-summary">
Formda 3 hata var
</div>
<script>
// Focus error summary programmatically
document.getElementById('error-summary').focus()
</script>Keyboard Event Handling
// ✅ Proper keyboard interaction
const button = document.querySelector('[role="button"]')
button.addEventListener('click', handleAction)
button.addEventListener('keydown', (e) => {
// Space ve Enter support
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault()
handleAction()
}
})
// ✅ Arrow key navigation
const items = document.querySelectorAll('[role="menuitem"]')
let currentIndex = 0
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
e.preventDefault()
currentIndex = (currentIndex + 1) % items.length
items[currentIndex].focus()
} else if (e.key === 'ArrowUp') {
e.preventDefault()
currentIndex = (currentIndex - 1 + items.length) % items.length
items[currentIndex].focus()
}
})Skip Links
<body>
<!-- Skip link - klavye kullanıcıları için -->
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<header>
<!-- Uzun navigation -->
</header>
<main id="main-content">
<!-- İçerik -->
</main>
</body>
<style>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
</style>Screen Reader Optimization
Descriptive Link Text
<!-- ❌ Kötü -->
<a href="/report.pdf">Buraya tıklayın</a>
<a href="/more">Devamı</a>
<!-- ✅ İyi -->
<a href="/report.pdf">
2024 Yıllık Raporu İndir (PDF, 2.3 MB)
</a>
<a href="/more">
Accessibility hakkında daha fazla bilgi
</a>Hiding Content Appropriately
<!-- Icon'ları screen reader'dan gizle -->
<button>
<span aria-hidden="true">🗑️</span>
Sil
</button>
<!-- Görsel olarak gizle ama screen reader'da oku -->
<style>
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style>
<button>
<span aria-hidden="true">📧</span>
<span class="sr-only">Email Gönder</span>
</button>Dynamic Content Announcements
// ✅ Screen reader announcement helper
function announce(message, priority = 'polite') {
const announcement = document.createElement('div')
announcement.setAttribute('role', 'status')
announcement.setAttribute('aria-live', priority)
announcement.setAttribute('aria-atomic', 'true')
announcement.classList.add('sr-only')
announcement.textContent = message
document.body.appendChild(announcement)
// Clean up after announcement
setTimeout(() => {
document.body.removeChild(announcement)
}, 1000)
}
// Usage
announce('Form başarıyla gönderildi')
announce('Hata oluştu: Email geçersiz', 'assertive')Color Contrast ve Visual Design
Minimum Contrast Ratios (WCAG 2.2 AA)
- Normal text: 4.5:1
- Large text (18pt+ or 14pt+ bold): 3:1
- UI components ve graphics: 3:1
/* ❌ Kötü - Yetersiz contrast */
.button {
background: #4A90E2; /* Blue */
color: #87CEEB; /* Light blue - 2.1:1 ratio */
}
/* ✅ İyi - Yeterli contrast */
.button {
background: #4A90E2;
color: #FFFFFF; /* White - 4.8:1 ratio */
}Focus Indicators (WCAG 2.2)
/* WCAG 2.4.11 - Focus Appearance (Enhanced) */
:focus-visible {
outline: 2px solid #4A90E2;
outline-offset: 2px;
/* Minimum 2px thickness, 3:1 contrast with adjacent colors */
}Target Size (WCAG 2.5.8)
/* Minimum 24x24 CSS pixels (AA) */
button, a {
min-width: 24px;
min-height: 24px;
padding: 8px 16px; /* Genellikle bunu sağlar */
}
/* Best practice: 44x44 (AAA ve mobile) */
.touch-target {
min-width: 44px;
min-height: 44px;
}Forms ve Input Accessibility
Proper Labels
<!-- ✅ Explicit label -->
<label for="username">Kullanıcı Adı:</label>
<input type="text" id="username" name="username" />
<!-- ✅ Implicit label -->
<label>
Email:
<input type="email" name="email" />
</label>
<!-- ✅ aria-label (son çare) -->
<input
type="search"
aria-label="Sitede ara"
placeholder="Ara..."
/>Error Handling
<form>
<label for="email">Email:</label>
<input
type="email"
id="email"
required
aria-required="true"
aria-invalid="false"
aria-describedby="email-error email-hint"
/>
<span id="email-hint">Örnek: ali@example.com</span>
<span id="email-error" role="alert" hidden>
Lütfen geçerli bir email girin
</span>
</form>
<script>
function validateEmail(input) {
const errorEl = document.getElementById('email-error')
if (!input.validity.valid) {
input.setAttribute('aria-invalid', 'true')
errorEl.hidden = false
errorEl.textContent = 'Lütfen geçerli bir email girin'
} else {
input.setAttribute('aria-invalid', 'false')
errorEl.hidden = true
}
}
</script>Required Fields
<!-- ✅ Multiple indicators -->
<label for="name">
İsim
<span aria-hidden="true">*</span>
<span class="sr-only">(zorunlu)</span>
</label>
<input
type="text"
id="name"
required
aria-required="true"
/>Testing ve Auditing
Automated Testing Tools
# axe-core - En comprehensive tool
npm install -D @axe-core/cli
# Run audit
axe https://yoursite.com
# Pa11y - CI/CD friendly
npm install -D pa11y
# Test
pa11y https://yoursite.comBrowser Extensions
- axe DevTools (Chrome, Firefox)
- WAVE (Chrome, Firefox, Edge)
- Accessibility Insights (Chrome, Edge)
Manual Testing Checklist
- Keyboard Navigation: Tüm functionality Tab/Enter/Arrow ile erişilebilir mi?
- Screen Reader: NVDA (Windows), JAWS (Windows), VoiceOver (Mac/iOS)
- Zoom: %200 zoom'da layout bozulmuyor mu?
- Color Blindness: Color filters ile test et
- Automated Tools: axe, WAVE, Lighthouse
CI/CD Integration
// cypress/e2e/accessibility.cy.js
import 'cypress-axe'
describe('Accessibility Tests', () => {
beforeEach(() => {
cy.visit('/')
cy.injectAxe()
})
it('Has no accessibility violations', () => {
cy.checkA11y()
})
it('Homepage accessible', () => {
cy.checkA11y('#main-content')
})
})Sık Sorulan Sorular
WCAG 2.2 compliance yasal zorunluluk mu?
AB'de European Accessibility Act (2025), ABD'de ADA Title III var. Türkiye'de kamu siteleri için zorunlu. E-ticaret ve özel sektörde de yaygınlaşıyor.
Level AAA gerekli mi?
Hayır, çoğu yasal gereklilik Level AA. AAA specialized content (örn: hastane, devlet) için.
Automated tools %100 güvenilir mi?
Hayır, automated tools sorunların sadece %30-40'ını yakalar. Manual testing ve screen reader testi şart.
Single Page Apps (SPA) için accessibility nasıl sağlanır?
Route değişimlerinde focus management, live region announcements, ve ARIA için ekstra dikkat gerekir.
Mobile app'ler için WCAG geçerli mi?
WCAG web için. Mobile için WCAG2ICT ve platform-specific (iOS Accessibility, Android TalkBack) guidelines var.
Color contrast checker önerisi?
WebAIM Contrast Checker, Stark plugin, Chrome DevTools built-in contrast checker.
Sonuç
Web accessibility 2025'te artık optional değil. WCAG 2.2 compliance, yasal gereklilikleri karşılamak, SEO iyileştirmek ve kullanıcı tabanınızı genişletmek için kritik.
İyi haber: Accessibility, genel kullanıcı deneyimini de iyileştirir. Semantic HTML, keyboard navigation, clear error messages herkes için faydalı.
Aksiyon Öğeleri:
- Sitenize axe DevTools extension ile audit yapın
- Heading hierarchy ve landmark'ları düzeltin
- Tüm images'a descriptive alt text ekleyin
- Keyboard-only navigation test edin
- Color contrast'ları düzeltin
- Form error handling'i iyileştirin
- Screen reader ile sitenizi test edin
Accessibility bir sprint değil marathon. Sürekli iyileştirme yapın, yeni features'larda baştan düşünün. Herkes için accessible web, better web demektir!
Projenizi Hayata Geçirelim
Web sitesi, mobil uygulama veya yapay zeka çözümü mü arıyorsunuz? Fikirlerinizi birlikte değerlendirelim.
Ücretsiz Danışmanlık Alın