Ana Sayfa / Blog / iOS accessibility: VoiceOver ve Dynamic Type için minimum disiplin

iOS accessibility: VoiceOver ve Dynamic Type için minimum disiplin

Accessibility feature'larını çoğu iOS developer afterthought olarak ekliyor. Pratikte hangi minimum şeyleri yapmak zorundayım?

iOS accessibility çok güçlü bir platform. Apple buna ciddi yatırım yapıyor. VoiceOver (ekran okuyucu), Dynamic Type (dinamik font boyutu), Reduce Motion, High Contrast, Voice Control, Switch Control. Kullanıcının ihtiyacına göre OS davranışını değiştiriyor.

Ama çoğu app bu feature’ları handle etmiyor. Developer “sonra bakarım” diyor ve hiç bakmıyor. 12 iOS uygulamamda minimum accessibility disiplinini koymayı rule yaptım. Bu yazıda pratik bir checklist’i paylaşacağım.

VoiceOver temel setup

VoiceOver ekrandaki elementleri okuyor, kullanıcı gesture’larla navigate ediyor. Temel kural: her interactive element okunabilir ve anlamlı olmalı.

SwiftUI’da otomatik varsayılanlar var. Text zaten okunuyor. Button’un label’ı okunuyor. Ama custom UI için manual:

Image("icon-share")
    .accessibilityLabel("Paylaş")
    .accessibilityHint("Bu içeriği paylaşmak için dokun")
  • accessibilityLabel: VoiceOver’ın okuyacağı text. Default image name (işe yaramaz) yerine anlamlı bir label.
  • accessibilityHint: Ek açıklama, action’ın ne yapacağı. “Paylaşma menüsünü açar” gibi.

Decorative vs informative images

Her image icon okunmasın. Decorative image’ları gizle:

Image("background-decoration")
    .accessibilityHidden(true)

Bu sayede VoiceOver arka plandaki süsleme icon’larını okumuyor, sadece bilgi veren image’ları okuyor.

Kural: eğer image bir bilgi iletiyorsa (“başarılı”, “uyarı”, “hata”) label ekle. Sadece süsleme ise hidden yap.

Group related elements

Kullanıcı VoiceOver ile item by item navigate ediyor. 10 elementin üzerinden tek tek geçmek yorucu. Related element’leri grupla:

HStack {
    Image("user-avatar")
    VStack {
        Text("Ahmet Yılmaz")
        Text("Software Engineer")
    }
}
.accessibilityElement(children: .combine)
.accessibilityLabel("Ahmet Yılmaz, Software Engineer")

Bu sayede 3 element (image + 2 text) tek bir element olarak okunuyor. Navigation hızlanıyor.

Dynamic Type (font scaling)

Kullanıcılar Settings > Display > Text Size’da font büyütebiliyor. Extra Small (12pt base) ile Accessibility XXX Large (53pt base) arası bir spectrum var.

Eski app’ler bunu handle etmiyor, fixed font kullanıyor. Kullanıcının text’i görmesi imkansız oluyor.

SwiftUI default olarak Dynamic Type’a responsive:

Text("Başlık")
    .font(.title)           // Dynamic Type friendly
    .font(.largeTitle)      // Dynamic Type friendly
    .font(.system(size: 16)) // Dynamic Type DEĞİL

System sizes (.title, .body, .caption) user preference’a göre scale oluyor. Manual size (.system(size: 16)) değişmiyor.

Kural: mümkünse system sizes. Özel size kullanman gerekiyorsa .dynamicTypeSize() modifier:

Text("custom")
    .font(.system(size: 16))
    .dynamicTypeSize(...DynamicTypeSize.accessibility5)

Layout dinamik font’a uyumlu olmalı

Font büyüyünce layout bozuluyor. Tipik problem: button text 2 satıra düşüyor, button height fixed, text kırpılıyor.

Fix: button height dynamic:

Button("Kaydet") { }
    .frame(maxWidth: .infinity)
    .padding(.vertical, 12)
    .background(Color.blue)
// NOT: .frame(height: 44) YAZMAYIN

Fixed height yerine padding. Text büyüdükçe button da büyüyor.

HStack’lerde multi-line overflow için:

HStack(alignment: .top) {
    Image("icon")
    Text("Uzun uzun bir label metni ki büyük font'ta iki satıra düşebilir")
}

alignment: .top ile multi-line text image ile top-align oluyor.

Color contrast

Default SwiftUI renkleri Apple standard accessibility contrast’a uygun. Custom renkler kullanıyorsan test et:

WCAG AA: 4.5:1 contrast ratio for normal text, 3:1 for large text.

Figma, Sketch, online tool’larla renk pair’lerini check et. Özellikle brand renkleri (light gray on white, kullanıcının okuyamayacağı).

SwiftUI’da Color.primary / Color.secondary kullanmak genelde güvenli. Dark mode ve light mode’da kendini adapt ediyor.

Focus state (navigation)

Keyboard kullanıcılar için focus state önemli. Hangi element seçili olduğu görünmeli:

Button("Seçenek 1") { }
    .focusable(true)
    .focused($isFocused)

Default SwiftUI button focus ring gösteriyor. Custom UI’da focus state’i kendin çizmelisin.

iPad’de external keyboard kullanıcıları, AppleTV, switch control kullanıcıları focus state’e bağımlı.

Reduce Motion

Bazı kullanıcılar motion animation’larından rahatsız (motion sickness, vestibular sensitivity). Settings > Accessibility > Motion > Reduce Motion.

App’inin check etmesi ve buna uyması gerekiyor:

@Environment(.accessibilityReduceMotion) var reduceMotion

// ...
.animation(reduceMotion ? nil : .easeOut, value: state)

Reduce Motion aktif ise animation’ları kapatıyor veya hafifletiyorsun. UIKit’te UIAccessibility.isReduceMotionEnabled flag.

Dark Mode + High Contrast

Dark mode default SwiftUI’da handle’lanıyor. Custom color’larda test et.

High Contrast mode (Settings > Accessibility > Display > Increase Contrast) background/foreground contrast’ı artırıyor. Default colors auto-adapt ediyor. Custom colors’da .preferredColorScheme ve high contrast variant’ları tanımla.

Testing

Accessibility test’in iki yöntemi:

1. Accessibility Inspector (Xcode > Open Developer Tool). Simulator’da UI’ı inspect et. Her element’in accessibility label’ı ne? Missing label var mı?

2. Gerçek VoiceOver’ı aç. Settings > Accessibility > VoiceOver. App’i 10-15 dakika VoiceOver ile kullan. İnanılmaz derecede ufuk açıcı.

3. Dynamic Type large size’da test et. Simulator’da Environment Override > Text Size > Accessibility XXX Large. App okunabiliyor mu, layout kırılıyor mu?

4. Reduced Motion test. Simulator’da açıp app’i dene.

Bu 4 test senin minimum disciplin’in olmalı her release öncesi.

Accessibility audit checklist

PR review’da şu sorular:

  • [ ] Her image anlamlı accessibilityLabel’a veya accessibilityHidden = true’ya sahip mi?
  • [ ] Her button/interactive element accessibilityLabel ve gerekirse accessibilityHint’e sahip mi?
  • [ ] Font size’lar system size mi, custom ise dynamic type destekli mi?
  • [ ] Fixed height button’lar var mı? Multi-line text’le bozulur mu?
  • [ ] Custom renkler accessibility contrast’ı geçiyor mu?
  • [ ] Animation’lar reduce motion’a uyumlu mu?
  • [ ] Test: Accessibility Inspector + VoiceOver ile 5 dakika test edildi mi?

Bu 7 madde %80 accessibility kalitesi sağlıyor.

Apple’ın accessibility assets

WWDC videolarında tonla accessibility session var. “SF Symbols in Your App” gibi generic session’lar bile accessibility tips içeriyor.

Apple’ın Accessibility Sample Code’ları mükemmel reference. Accessibility Inspector build-in tool.

iOS 18 ile daha fazla accessibility API geldi: Music Haptics, Live Captions, Eye Tracking, Vocal Shortcuts. Gelişmeler agresif, takip etmek değerli.

Business case

Accessibility feature’ları kullanıcı tabanının önemli bir bölümü tarafından kullanılıyor:

  • Dynamic Type’ı büyük size’da kullanan: %15-20
  • VoiceOver daily: %1-2
  • Reduce Motion: %3-5
  • High Contrast: %2-3

Bu yüzde’ler toplamda app kullanıcılarının %25-30’u demek. Ciddi bir audience. Accessibility’yi ignore etmek bu audience’i kaybetmek.

Ayrıca bazı ülkelerde legal requirement. ADA compliance (US), EN 301 549 (EU), Türkiye’de de benzer yasal düzenlemeler mevcut.

Sonuç

Accessibility afterthought değil, baseline olmalı. Her release’de bir 10-15 dakika VoiceOver + accessibility inspector test. Checklist disiplini PR review’da.

Bu minimum investment accessibility-friendly bir app veriyor, gelişmiş senaryolar için sonra iterate edersin. İlk başta perfect olmak zorunda değilsin, ama baseline karşılanmış olmalı.

Bu konuda bir projeniz mi var?

Kısa bir özet bırakın, 24 saat içinde size dönüş yapayım.

İletişime Geç