Content Description — właściwość dostępności, która przekazuje opis tekstowy nietekstowej treści technologiom asystującym. W iOS jest to atrybut accessibilityHint dla UIView, w Android — contentDescription w znacznikach XML. Według danych W3C WCAG 2.2, 2023, brak alternatyw tekstowych dla treści nietekstowej — jedno z najczęstszych naruszeń dostępności w aplikacjach mobilnych. Prawidłowo wypełnione opisy sprawiają, że aplikacja jest dostępna dla osób z wadami wzroku korzystających z VoiceOver i TalkBack.
Najważniejsze
Content Description — to właściwość łańcuchowa elementu interfejsu, która przekazuje tekstową reprezentację treści wizualnej technologiom asystującym. Screen reader (VoiceOver w iOS, TalkBack w Android) odczytuje opis zamiast próbować rozpoznać element wizualnie. Opis stosuje się do obrazów bez warstwy tekstowej, ikon, wykresów, niestandardowych kontrolek i wszelkich elementów nietekstowych.
Według danych Google Material Design, 2024, elementy bez contentDescription naruszają regułę WCAG 1.1.1 (Non-text Content). Sprawdzanie Accessibility Scanner pokazuje, że do 40% ikon w aplikacjach sklepowych nie ma opisu. Użytkownik VoiceOver słyszy „obraz” lub „przycisk” bez doprecyzowania — taki interfejs staje się nieprzydatny do nawigacji.
Content Description nie zastępuje widocznego tekstu elementu. Jeśli przycisk zawiera tekstową etykietę „Wyślij”, nie trzeba dodawać dodatkowego opisu — screen reader odczyta tekst. W przypadku obrazów, ikon i pól wejściowych opis jest obowiązkowy.
Narzędzie Accessibility Scanner (Android) i Xcode Accessibility Inspector (iOS) automatycznie sprawdzają obecność opisów. Zaleca się przeprowadzanie tych kontroli na każdym ekranie przed wersją.
Użytkownik z wadą wzroku polega na VoiceOver, aby zrozumieć interfejs. Jeśli ikona koszyka nie ma opisu, słyszy tylko „przycisk”. Aby dowiedzieć się, co robi przycisk, musi go nacisnąć na ślepo — ryzyko nieodwracalnej akcji. Opis „Usuń produkt z koszyka” rozwiązuje ten problem w sekundę.
Użytkownik z tymczasowymi ograniczeniami (mocne słońce na zewnątrz, zepsuty ekran) również używa VoiceOver. Według danych Apple Accessibility Report, 2023, około 20% użytkowników VoiceOver nie ma stałych wad wzroku — włączają tę funkcję sytuacyjnie.
Kryterium WCAG 1.1.1 (poziom A) wymaga, aby każda treść nietekstowa miała alternatywę tekstową. Wyjątek: treść, która jest dekoracyjna, używana tylko do wizualnego wyglądu lub nie niesie informacji. Test na dekoracyjność: jeśli usunąć element, czy zmieni się sens strony? Jeśli nie — można ukryć przed screen readerem.
Accessibility Label (accessibilityLabel w iOS) — to nazwa elementu, którą screen reader wypowiada przy fokusie. Content Description (accessibilityHint w iOS) — dodatkowe wyjaśnienie, które jest odczytywane po nazwie i informuje o wyniku działania.
Różnica jest dobrze widoczna na przykładzie przycisku „Koszyk”. Label: „Koszyk”. Description: „Otworzy ekran składania zamówienia”. VoiceOver wypowiada: „Koszyk. Otworzy ekran składania zamówienia”. Jeśli ustawić tylko Label, użytkownik nie dowie się, co stanie się po naciśnięciu.
| Właściwość | iOS | Android | Przeznaczenie |
|---|---|---|---|
| Label | accessibilityLabel | contentDescription | Nazwa elementu (przycisk, pole, obraz) |
| Description | accessibilityHint | contentDescription (rozszerzona) | Wyjaśnienie działania lub znaczenia |
| Trait | accessibilityTraits | role / className | Rola elementu (przycisk, nagłówek) |
Zasada: Label odpowiada na pytanie „Co to jest?”, Description — „Co się stanie?”. W Android contentDescription może pełnić obie role, ale w praktyce lepiej rozdzielać: używać konkatenacji „[nazwa], [wyjaśnienie]”.
W przypadku złożonych gestów (przesunięcie w celu usunięcia, długie naciśnięcie dla menu kontekstowego) accessibilityHint jest obowiązkowy. Użytkownik VoiceOver nie wie o ukrytych gestach, jeśli nie są opisane. Należy wskazać: „Przesuń w lewo, aby usunąć” w hincie elementu.
W platformie iOS accessibilityHint ustawia się poprzez właściwość UIView lub NSObject. Wartość — ciąg do 80 znaków. VoiceOver odczytuje hint po label, jeśli włączony jest tryb szczegółowych opisów (w ustawieniach VoiceOver — „Verbosity”).
Przykład ustawienia hint dla niestandardowego przycisku:
import UIKit
class CustomButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
self.accessibilityLabel = "Dodaj do ulubionych"
self.accessibilityHint = "Zapisze produkt na liście ulubionych"
}
}
Dla UIImageView bez treści tekstowej należy obowiązkowo ustawić isAccessibilityElement = true i accessibilityHint:
let imageView = UIImageView(image: UIImage(named: "chart-sales"))
imageView.isAccessibilityElement = true
imageView.accessibilityHint = "Wykres sprzedaży za ostatni kwartał"
VoiceOver czyta: „Wykres sprzedaży za ostatni kwartał”. Jeśli hint jest pusty — tylko „obraz”. Apple HIG, 2024 zaleca nie używać w hincie czasowników w rodzaju „naciśnij” lub „dotknij” — VoiceOver automatycznie dodaje instrukcję gestu.
W SwiftUI hint ustawia się przez modyfikator chain:
Image(systemName: "trash")
.accessibilityLabel("Usuń")
.accessibilityHint("Nieodwracalnie usunie wybrany element")
SwiftUI automatycznie łączy modyfikatory dla złożonych widoków. Jeśli Image znajduje się wewnątrz Button, SwiftUI używa label przycisku jako głównego accessibilityLabel.
W Android contentDescription ustawia się albo w znacznikach XML, albo programowo przez setContentDescription(). TalkBack odczytuje opis przy fokusie na elemencie.
Przykład w XML:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_search"
android:contentDescription="Wyszukiwanie produktów" />
Programowe ustawienie dla dynamicznych elementów:
binding.iconSearch.contentDescription =
"Wyszukiwanie. Otworzy ekran wyszukiwania z filtrami"
Dla obrazów dekoracyjnych (separatory, tła, dekoracyjne ikony) należy ustawić contentDescription = "@null" lub setContentDescription(null) — TalkBack pominie taki element. W XML: android:contentDescription="@null". Pusty ciąg "" nie działa — TalkBack i tak odczyta „obraz”.
Dla ImageButton zawsze ustawiaj contentDescription — TalkBack nie widzi tekstu na obrazie. Dla CheckBox opis powinien dynamicznie się zmieniać: „Wybrany” / „Nie wybrany” zamiast statycznego opisu. Użyj setContentDescription w słuchaczu stanu.
Informacyjność — opis powinien przekazywać znaczenie, a nie wygląd zewnętrzny. Nie „Niebieska ikona z haczykiem”, a „Produkt dodany do koszyka”. Screen reader nie interesuje się kolorami — interesuje go rezultat.
Zręczność — optymalna długość 2–4 słowa (do 80 znaków). Długie opisy opóźniają nawigację: VoiceOver czyta sekwencyjnie, każde słowo to sekunda czasu użytkownika. Według danych Apple WWDC 2023, „Accessibility by Design”, fraza dłuższa niż 5 sekund czytania przerywa przepływ poznawczy.
Unikalność — na jednym ekranie nie powinno być dwóch elementów z tym samym opisem. Użytkownik nie będzie w stanie odróżnić, który rezultat wywoła fokus na pierwszym i na drugim elemencie. Jeśli przycisków „Kup” jest kilka — dodaj identyfikator: „Kup iPhone 15”, „Kup iPhone 15 Pro”.
Lokalizacja — Content Description tłumaczy się na wszystkie języki, które obsługuje aplikacja. Błąd lokalizacji opisu — jedna z częstych przyczyn niepowodzenia Accessibility Review w App Store.
Badanie Nielsen Norman Group, 2024 pokazało, że optymalna długość opisu dla screen readera to 3–5 słów (do 50 znaków). Dłuższe opisy zmniejszają prędkość nawigacji o 30%, ponieważ użytkownik musi czekać na zakończenie odtwarzania przed następnym krokiem.
Nadmiarowość — opis powiela widoczny tekst. Jeśli przycisk zawiera tekst „Wyślij”, nie ustawiaj accessibilityHint = „Przycisk wyślij”. VoiceOver odczyta tekst automatycznie, a hint doda niepotrzebny szum.
Mylenie z Label — używanie contentDescription zamiast label dla przycisków tekstowych. W iOS accessibilityLabel powinien pokrywać się z tekstem przycisku (lub być pusty, jeśli tekst jest już widoczny), a hint — tylko wyjaśniać działanie. Według danych Google Testing Blog, 2024, 23% sprawdzonych aplikacji w Play Store ma powielające się opisy.
Ignorowanie dynamiki — opis nie aktualizuje się przy zmianie stanu. Na przykład u przełącznika „Wi-Fi” opis pozostaje „Włącz Wi-Fi” nawet po włączeniu. Prawidłowo: dynamicznie zmieniać opis na „Wyłącz Wi-Fi” poprzez obserwację stanu.
Po aktualizacji projektu (zmiana ikon, przestawienie elementów) Content Description często ginie. Przyczyna: projektant zastępuje obraz, programista nie sprawdza właściwości dostępności nowego zasobu. Rozwiązanie: uczynić sprawdzanie dostępności obowiązkowym krokiem code review — dodać listę kontrolną z punktem „Content Description zaktualizowany?”.
func testContentDescriptionExists() {
let app = XCUIApplication()
app.launch()
let image = app.images["chart-sales"]
XCTAssertNotNil(image.label)
XCTAssertGreaterThan(image.label.count, 0)
}
Często zadawane pytania
Użytkownik VoiceOver lub TalkBack usłyszy po prostu „obraz” lub „przycisk” — bez wskazania przeznaczenia. To narusza WCAG 1.1.1 i sprawia, że aplikacja staje się niedostępna dla osób z wadami wzroku.
Nie. Jeśli przycisk zawiera etykietę tekstową, VoiceOver odczyta ją automatycznie. Opis (accessibilityHint) można dodać w celu wyjaśnienia wyniku naciśnięcia, ale Label nie jest wymagany.
W iOS ustaw isAccessibilityElement = false. W Android ustaw contentDescription = "@null". Screen reader całkowicie pominie taki element, nie wydając dźwięku.
W iOS użyj NSLocalizedString dla accessibilityHint, w Android — zasobów łańcuchowych przez @string/. Tłumaczenie opisów jest obowiązkowe dla wszystkich obsługiwanych języków.
Dodaj testy UI, które sprawdzają obecność opisu dla wszystkich ImageView. W iOS — XCUIApplication, w Android — AccessibilityCheckRule z Espresso. Accessibility Scanner można uruchomić w CI przez wiersz poleceń.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również