Accessibility Label to nazwa elementu interfejsu, którą VoiceOver (iOS) lub TalkBack (Android) wypowiada po ustawieniu fokusu. W iOS właściwość nazywa się accessibilityLabel, w Android — contentDescription dla elementów niezawierających tekstu. Według Apple Developer Documentation, 2024, etykieta to podstawa dostępności: bez niej użytkownik nie może zidentyfikować elementu. Etykieta powinna być unikalna w obrębie ekranu i odzwierciedlać istotę elementu zrozumiałym językiem.
Najważniejsze
Accessibility Label to właściwość tekstowa określająca nazwę elementu dla technologii asystujących. Gdy użytkownik przesuwa palcem po ekranie z włączonym VoiceOver, czytnik ekranu odczytuje Label elementu, na którym znajduje się fokus. Bez etykiety użytkownik słyszy tylko typ elementu: „przycisk”, „obraz” — bez określenia przeznaczenia.
Według Google I/O 2024, „Accessibility Testing”, 35% krytycznych naruszeń dostępności w aplikacjach sklepowych jest związanych z brakiem lub nieprawidłowym Label. Accessibility Scanner na Android wykrywa brak etykiety jako błąd najwyższej wagi.
Zasadnicze ograniczenie: Label nie powinien zawierać typu elementu. VoiceOver i TalkBack automatycznie dodają rolę (button, header, link) w komunikacie. Jeśli Label zawiera „Przycisk wysyłania”, użytkownik usłyszy: „Przycisk wysyłania, przycisk” — powielenie.
WCAG 4.1.2 (poziom A) wymaga, aby każdy element interfejsu użytkownika miał programowo określoną nazwę (name), rolę (role) i wartość (value). Accessibility Label zapewnia name. Jeśli Label brakuje, kryterium jest uznawane za naruszone, a aplikacja nie przechodzi podstawowej certyfikacji.
W iOS accessibilityLabel jest dziedziczony przez wszystkie UIView z protokołu UIAccessibility. Jeśli element zawiera tekst (UIButton z title, UILabel z text), Label jest automatycznie ustawiany na ten tekst. Dla UIImageView, niestandardowych kontrolek i kontenerów Label trzeba ustawić ręcznie.
Przykład dla niestandardowej komórki tabeli:
class CustomTableViewCell: UITableViewCell {
let titleLabel = UILabel()
let priceLabel = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
self.isAccessibilityElement = true
self.accessibilityLabel =
"\(titleLabel.text ?? "") - \(priceLabel.text ?? "")"
}
}
Dla niestandardowych UIView można nadpisać getter accessibilityLabel:
class RatingView: UIView {
var rating: Int = 5
override var accessibilityLabel: String? {
get { return "Ocena: \(rating) z 5" }
set {}
}
}
Apple HIG, 2024 zaleca: jeśli element składa się z kilku subelementów (np. karta produktu z nazwą i ceną), połącz je w jeden accessibility-element złożoną etykietą. Ustaw isAccessibilityElement = true na rodzicu i false na dzieciach.
Jeśli UILabel używa NSAttributedString, accessibilityLabel domyślnie jest równy .string (plain text). Jeśli potrzebujesz przekazać semantycznie inną wartość (np. ikona-symbol czytana jako „Gwiazda” zamiast symbolu ★), jawnie ustaw accessibilityLabel. VoiceOver nie czyta symboli Unicode w sposób zrozumiały.
W Android contentDescription pełni funkcję Label dla ImageView, ImageButton i niestandardowych View. Dla TextView i Button z wbudowanym tekstem nie trzeba ustawiać contentDescription — TalkBack czyta tekst automatycznie.
Programowe ustawienie przez Kotlin:
binding.iconStar.contentDescription = "Produkt w ulubionych"
// Dla niestandardowego widoku z wieloma elementami
binding.customCard.setContentDescription(
"\(title) za kwotę \(price)")
W XML dla elementów dekoracyjnych:
<ImageView
android:contentDescription="@null"
android:src="@drawable/divider"
android:importantForAccessibility="no" />
Właściwość importantForAccessibility = "no" całkowicie wyklucza element z drzewa dostępności. W iOS odpowiednik to isAccessibilityElement = false.
W Jetpack Compose Label ustawia się przez modyfikator semantics:
Image(
painter = painterResource(R.drawable.ic_search),
contentDescription = "Wyszukiwanie produktów",
modifier = Modifier.semantics {
contentDescription = "Wyszukiwanie produktów"
}
)
W Compose contentDescription to obowiązkowy parametr dla Image — bez niego kod się nie skompiluje (warning). To wymusza poprawę dostępności poprzez projekt API.
Accessibility Label odpowiada na pytanie „Co to za element?”. Hint (accessibilityHint w iOS, dodatkowy tekst w contentDescription w Android) — „Co się stanie przy interakcji?”. VoiceOver wypowiada je kolejno: najpierw Label, potem Hint.
Przykład dla przycisku usuwania:
Według Deque University, 2024, prawidłowe rozdzielenie Label i Hint zwiększa wskaźnik powodzenia wykonywania zadań dla użytkowników VoiceOver o 28%. Użytkownicy z zaburzeniami poznawczymi są szczególnie zależni od Hint: ryzykując naciśnięcie „Usuń” bez wyjaśnienia, 40% rezygnuje z działania.
Częsty błąd: w Label piszą „Przycisk usuwania” zamiast „Usuń”. Typ elementu (Button) jest dodawany przez VoiceOver automatycznie poprzez trait. W rezultacie użytkownik słyszy: „Przycisk usuwania, przycisk” — powielenie. Prawidłowy Label: „Usuń”, Hint: „Usunie wybrane zdjęcie”.
Lokalizacja etykiet jest obowiązkowa — odbywa się poprzez standardowe mechanizmy: NSLocalizedString w iOS, zasoby ciągów @string/ w Android. Nigdy nie ustawiaj Label przez konkatenację po angielsku bez lokalizacji.
Zasady dobrego Label, oparte na W3C WCAG 2.2:
Używaj jednolitego glosariusza dla Label w aplikacji. Jeśli na jednym ekranie jest napisane „Ulubione”, a na drugim „Zakładki”, użytkownik jest zdezorientowany. Stwórz tabelę terminów dostępności — uzgodnij z projektantami i lokalizatorami.
Dla pól wprowadzania (UITextField, EditText) Label powinien być zgodny z placeholderem lub tytułem pola. Jednak placeholder często znika po wprowadzeniu tekstu. Używaj accessibilityLabel dla stałej nazwy i accessibilityValue dla bieżącej zawartości pola — to standard WCAG 4.1.2. Rozwiązanie: ustaw accessibilityLabel statycznie (równy tytułowi pola), a accessibilityValue dynamicznie (równy wprowadzonemu tekstowi). W iOS jest to automatyczne, ale dla niestandardowych pól — ręcznie przez nadpisanie accessibilityValue. Sprawdź, czy VoiceOver czyta: „Email, example@domain.com, pole tekstowe” zamiast „, pole tekstowe”.
Zautomatyzowane testowanie to jedyny sposób zagwarantowania poprawności Label na wszystkich ekranach. iOS udostępnia XCUIApplication z dostępem do .label, Android — AccessibilityCheckRule i setContentDescription.
Przykład testu dla iOS:
func testLabelsAreUnique() {
let app = XCUIApplication()
app.launch()
let allButtons = app.buttons.allElementsBoundByIndex
let labels = allButtons.compactMap { $0.label }
let uniqueLabels = Set(labels)
XCTAssertEqual(labels.count, uniqueLabels.count,
"Znaleziono duplikujące się Label")
}
Przykład dla Android z Espresso:
@Test
fun testButtonHasAccessibilityLabel() {
onView(withId(R.id.btnSubmit))
.check(matches(
withContentDescription(containsString("Wyślij"))
))
}
Testowanie ręczne: włącz VoiceOver (iOS) lub TalkBack (Android) i przesuń gestem w prawo po wszystkich elementach ekranu. Każdy element powinien otrzymać sensowny komunikat. Jeśli słyszysz tylko „przycisk” lub „obraz” — Label brakuje.
Po skonfigurowaniu Label użytkownik VoiceOver może używać rotora do szybkiej nawigacji: tryby „Przyciski”, „Nagłówki”, „Linki” i inne. Jeśli Label jest poprawnie ustawiony, VoiceOver włącza element do odpowiedniego trybu rotora. Sprawdź, czy wszystkie przyciski są widoczne w trybie „Przyciski”, a wszystkie nagłówki w „Nagłówki”.
Label wpływa również na wyszukiwanie VoiceOver. Użytkownik może wpisać słowo w trybie wyszukiwania, a VoiceOver przeniesie fokus na element z pasującym Labelem. Dlatego w Label powinny znajdować się słowa kluczowe, po których użytkownik będzie szukać elementu.
Dodaj sprawdzanie Label do pipeline. Na iOS używaj XCUITest z fastlane scan. Na Android — Accessibility Test Framework z regułą AccessibilityCheckRule, która wykrywa puste contentDescription. Zapobiega to regresjom przy scalaniu nowych ekranów.
Często zadawane pytania
Label identyfikuje element („Wyszukiwanie”), Hint wyjaśnia rezultat działania („Otworzy ekran wyszukiwania”). VoiceOver wypowiada Label natychmiast po ustawieniu fokusu, a Hint w trybie szczegółowych opisów.
W iOS UILabel automatycznie otrzymuje accessibilityLabel równy swojemu tekstowi. Nie trzeba go dodatkowo ustawiać. W Android TextView zachowuje się analogicznie.
Ustaw isAccessibilityElement = true na widoku nadrzędnym i nadpisz accessibilityLabel, zwracając skonkatenowany tekst z elementów podrzędnych. Dla złożonych komponentów używaj połączenia z separatorem.
Dodawaj kontekst do powtarzających się elementów: „Kup iPhone 15”, „Kup iPhone 15 Pro”. Automatyzuj sprawdzanie przez testy UI — zbieraj wszystkie Label i sprawdzaj brak duplikatów.
Nie. Do ukrycia elementu używaj isAccessibilityElement = false w iOS lub importantForAccessibility = "no" w Android. Pusty Label nie ukrywa elementu — czytnik ekranu odczyta „bez nazwy”.
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ż