Accessibility Label — це ім’я елемента інтерфейсу, яке VoiceOver (iOS) або TalkBack (Android) вимовляє при фокусі. У iOS властивість називається accessibilityLabel, у Android — contentDescription для елементів, що не містять тексту. Згідно з Apple Developer Documentation, 2024, мітка є основою доступності: без неї користувач не може ідентифікувати елемент. Мітка повинна бути унікальною в межах екрану та відображати суть елемента зрозумілою мовою.
Головне
Accessibility Label — це рядкова властивість, яка визначає ім’я елемента для допоміжних технологій. Коли користувач проводить пальцем по екрану з увімкненим VoiceOver, екранний читач зчитує мітку елемента, на якому знаходиться фокус. Без мітки користувач чує лише тип елемента: «кнопка», «зображення» — без зазначення призначення.
Згідно з Google I/O 2024, «Accessibility Testing», 35% критичних порушень доступності в магазинних додатках пов’язані з відсутністю або некоректністю міток. Accessibility Scanner на Android виявляє відсутність мітки як помилку найвищої серйозності.
Основоположне обмеження: Мітка не повинна містити тип елемента. VoiceOver та TalkBack автоматично додають роль (кнопка, заголовок, посилання) до оголошення. Якщо мітка містить «Кнопка відправлення», користувач почує: «Кнопка відправлення, кнопка» — дублювання.
WCAG 4.1.2 (рівень A) вимагає, щоб кожен елемент користувацького інтерфейсу мав програмно визначувані ім’я, роль та значення. Accessibility Label надає ім’я. Якщо мітка відсутня, критерій вважається порушеним, і додаток не проходить базову сертифікацію.
У iOS accessibilityLabel успадковується всіма UIView від протоколу UIAccessibility. Якщо елемент містить текст (UIButton з назвою, UILabel з текстом), мітка автоматично встановлюється на цей текст. Для UIImageView, користувацьких контролів та контейнерів мітку потрібно задавати вручну.
Приклад для користувацької комірки таблиці:
class CustomTableViewCell: UITableViewCell {
let titleLabel = UILabel()
let priceLabel = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
self.isAccessibilityElement = true
self.accessibilityLabel =
"\(titleLabel.text ?? "") - \(priceLabel.text ?? "")"
}
}
Для користувацьких UIView можна перевизначити гетер accessibilityLabel:
class RatingView: UIView {
var rating: Int = 5
override var accessibilityLabel: String? {
get { return "Оцінка: \(rating) з 5" }
set {}
}
}
Apple HIG, 2024 радить: якщо елемент складається з кількох піделементів (наприклад, картка товару з назвою та ціною), об’єднайте їх в один елемент доступності з складеною міткою. Встановіть isAccessibilityElement = true на батьківському елементі та false на дочірних.
Якщо UILabel використовує NSAttributedString, accessibilityLabel типово дорівнює .string (звичайний текст). Якщо потрібно передати семантично інше значення (наприклад, значок-символ читається як «Зірка» замість символу ★), явно встановіть accessibilityLabel. VoiceOver не читає символи Unicode осмислено.
У Android contentDescription виконує функцію Label для ImageView, ImageButton та користувацьких View. Для TextView та Button зі вбудованим текстом задавати contentDescription не потрібно — TalkBack читає текст автоматично.
Програмне задання через Kotlin:
binding.iconStar.contentDescription = "Товар в обраному"
// Для користувацького View з багатьома елементами
binding.customCard.setContentDescription(
"\(title) на суму \(price)")
У XML для декоративних елементів:
<ImageView
android:contentDescription="@null"
android:src="@drawable/divider"
android:importantForAccessibility="no" />
Властивість importantForAccessibility = «no» повністю виключає елемент з дерева доступності. У iOS аналогом є isAccessibilityElement = false.
У Jetpack Compose Label задається через модифікатор semantics:
Image(
painter = painterResource(R.drawable.ic_search),
contentDescription = "Пошук товарів",
modifier = Modifier.semantics {
contentDescription = "Пошук товарів"
}
)
У Compose contentDescription — це обов’язковий параметр для Image — без нього код не скомпілюється (попередження). Це примусово покращує доступність через дизайн API.
Accessibility Label відповідає на запитання «Що це за елемент?». Hint (accessibilityHint у iOS, додатковий текст у contentDescription у Android) — «Що відбудеться при взаємодії?». VoiceOver вимовляє їх послідовно: спочатку Label, потім Hint.
Приклад для кнопки видалення:
Згідно з Deque University, 2024, правильне розділення Label та Hint підвищує рівень виконання завдань для користувачів VoiceOver на 28%. Користувачі з когнітивними порушеннями особливо залежні від Hint: не будучи впевненими щодо натискання «Видалити» без пояснення, 40% відмовляються від дії.
Часта помилка: у Label пишуть «Кнопка видалення» замість «Видалити». Тип елемента (Кнопка) додається VoiceOver автоматично через трейт. У результаті користувач чує: «Кнопка видалення, кнопка» — дублювання. Правильний Label: «Видалити», Hint: «Видаляє вибране фото».
Локалізація міток обов’язкова — вона здійснюється через стандартні механізми: NSLocalizedString у iOS, рядкові ресурси @string/ у Android. Ніколи не задавайте мітку конкатенацією англійською без локалізації.
Правила хорошої мітки, засновані на W3C WCAG 2.2:
Використовуйте єдиний глосарій для міток у всьому додатку. Якщо на одному екрані написано «Улюблені», а на іншому «Закладки», користувач дезорієнтований. Створіть таблицю термінів доступності — узгодьте з дизайнерами та локалізаторами.
Для полів введення (UITextField, EditText) Label повинен збігатися з placeholder або підписом поля. Однак placeholder часто зникає після введення тексту. Використовуйте accessibilityLabel для постійного імені та accessibilityValue для поточного вмісту поля — це стандарт WCAG 4.1.2. Рішення: встановіть accessibilityLabel статично (рівним підпису поля) та accessibilityValue динамічно (рівним введеному тексту). У iOS це автоматично, але для користувацьких полів — вручну через перевизначення accessibilityValue. Перевірте, що VoiceOver читає: «Електронна пошта, приклад@домен.com, текстове поле» замість «, текстове поле».
Автоматизоване тестування — єдиний спосіб гарантувати коректність Label на всіх екранах. iOS надає XCUIApplication з доступом до .label, Android — AccessibilityCheckRule та setContentDescription.
Приклад тесту для 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,
"Знайдено дублюючіся Label")
}
Приклад для Android з Espresso:
@Test
fun testButtonHasAccessibilityLabel() {
onView(withId(R.id.btnSubmit))
.check(matches(
withContentDescription(containsString("Надіслати"))
))
}
Ручне тестування: увімкніть VoiceOver (iOS) або TalkBack (Android) та проведіть пальцем вправо по всіх елементах екрану. Кожен елемент повинен отримати осмислене оголошення. Якщо ви чуєте лише «кнопка» або «зображення» — Label відсутній.
Після налаштування Label користувачі VoiceOver можуть використовувати ротор для швидкої навігації: режими «Кнопки», «Заголовки», «Посилання» та інші. Якщо Label задано правильно, VoiceOver включає елемент в відповідний режим ротора. Перевірте, що всі кнопки видні в режимі «Кнопки», а всі заголовки в «Заголовки».
Label також впливає на пошук VoiceOver. Користувач може ввести слово в режимі пошуку, і VoiceOver перемістить фокус на елемент з відповідним Label. Тому Label повинні містити ключові слова, за якими користувач буде шукати.
Додайте перевірку Label у пайплайн. На iOS використовуйте XCUITest з fastlane scan. На Android використовуйте Accessibility Test Framework з правилом AccessibilityCheckRule, яке виявляє порожні contentDescription. Це запобігає регресіям при злитті нових екранів.
Часто задавані питання
Label ідентифікує елемент («Пошук»), Hint пояснює результат дії («Відкриє екран пошуку»). VoiceOver вимовляє Label одразу при фокусі, а Hint — у режимі детальних описів.
У iOS UILabel автоматично отримує accessibilityLabel, рівний своєму тексту. Додатково задавати не потрібно. У Android TextView поводиться аналогічно.
Встановіть isAccessibilityElement = true на батьківському View та перевизначте accessibilityLabel, повернувши конкатенований текст з дочірних елементів. Для складних компонентів використовуйте об’єднання з роздільником.
Додавайте контекст до повторюваних елементів: «Купити iPhone 15», «Купити iPhone 15 Pro». Автоматизуйте перевірку через UI-тести — збирайте всі Label та перевіряйте відсутність дублікатів.
Ні. Для приховування елемента використовуйте isAccessibilityElement = false у iOS або importantForAccessibility = «no» у Android. Порожній Label не приховує елемент — екранний читач прочитає «без назви».
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також