Accessibility Label — что это такое, основы и как использовать для iOS и Android

Автор: IT Sectr Опубликовано: 2026-05-16 Время чтения: 9 мин

Accessibility Label — это имя элемента интерфейса, которое VoiceOver (iOS) или TalkBack (Android) произносит при фокусе. В iOS свойство называется accessibilityLabel, в Android — contentDescription для элементов, не содержащих текст. По данным Apple Developer Documentation, 2024, метка — основа доступности: без неё пользователь не может идентифицировать элемент. Метка должна быть уникальной в пределах экрана и отражать суть элемента понятным языком.

Главное

  • Accessibility Label — имя элемента, которое озвучивает screen reader; задаётся через accessibilityLabel в iOS и contentDescription в Android
  • Label должен совпадать с видимым текстом элемента или заменять его для нетекстовых компонентов
  • Каждый Label обязан быть уникальным в пределах экрана — дублирующие метки дезориентируют пользователя
  • Локализация Label обязательна: метки переводятся на все поддерживаемые языки приложения
  • Для кастомных контролов Label задаётся программно через переопределение свойства или NSObject протокола

Что такое Accessibility Label

Accessibility Label — это строковое свойство, определяющее имя элемента для вспомогательных технологий. Когда пользователь проводит пальцем по экрану с включённым VoiceOver, screen reader зачитывает Label элемента, на котором находится фокус. Без метки пользователь слышит только тип элемента: «кнопка», «изображение» — без указания назначения.

По данным Google I/O 2024, «Accessibility Testing», 35% критических accessibility-нарушений в магазинных приложениях связаны с отсутствием или некорректностью Label. Accessibility Scanner на Android детектирует отсутствие метки как ошибку highest severity.

Принципиальное ограничение: Label не должен содержать тип элемента. VoiceOver и TalkBack автоматически добавляют роль (button, header, link) в объявление. Если Label содержит «Кнопка отправки», пользователь услышит: «Кнопка отправки, кнопка» — дублирование.

Label и WCAG 4.1.2: Name, Role, Value

WCAG 4.1.2 (уровень A) требует, чтобы каждый элемент пользовательского интерфейса имел программно определяемое имя (name), роль (role) и значение (value). Accessibility Label обеспечивает name. Если Label отсутствует, критерий считается нарушенным, и приложение не проходит базовую сертификацию.

iOS: свойство accessibilityLabel

В iOS accessibilityLabel наследуется всеми UIView от протокола UIAccessibility. Если элемент содержит текст (UIButton с title, UILabel с text), Label автоматически устанавливается равным этому тексту. Для UIImageView, кастомных контролов и контейнеров Label нужно задавать вручную.

Пример для кастомной ячейки таблицы:

swift
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:

swift
class RatingView: UIView {
    var rating: Int = 5

    override var accessibilityLabel: String? {
        get { return "Оценка: \(rating) из 5" }
        set {}
    }
}

Apple HIG, 2024 советует: если элемент состоит из нескольких субэлементов (например, карточка товара с названием и ценой), объедините их в один accessibility-элемент с композитным Label. Установите isAccessibilityElement = true на родителе и false на детях.

NSAttributedString и accessibilityLabel

Если UILabel использует NSAttributedString, accessibilityLabel по умолчанию равен .string (plain text). Если нужно передать семантически другое значение (например, иконка-символ читается как «Звезда» вместо символа ★), явно установите accessibilityLabel. VoiceOver не читает Unicode-символы осмысленно.

Android: Label через contentDescription

В Android contentDescription выполняет функцию Label для ImageView, ImageButton и кастомных View. Для TextView и Button со встроенным текстом задавать contentDescription не требуется — TalkBack читает текст автоматически.

Программное задание через Kotlin:

kotlin
binding.iconStar.contentDescription = "Товар в избранном"

// Для кастомной View с множественными элементами
binding.customCard.setContentDescription(
    "\(title) на сумму \(price)")

В XML для декоративных элементов:

xml
<ImageView
    android:contentDescription="@null"
    android:src="@drawable/divider"
    android:importantForAccessibility="no" />

Свойство importantForAccessibility = "no" полностью исключает элемент из дерева доступности. В iOS аналог — isAccessibilityElement = false.

Compose: semantics и contentDescription

В Jetpack Compose Label задаётся через модификатор semantics:

kotlin
Image(
    painter = painterResource(R.drawable.ic_search),
    contentDescription = "Поиск товаров",
    modifier = Modifier.semantics {
        contentDescription = "Поиск товаров"
    }
)

В Compose contentDescription — обязательный параметр для Image, без него код не скомпилируется (warning). Это принудительно улучшает accessibility через дизайн API.

Label и Hint: различие ролей

Accessibility Label отвечает на вопрос «Что это за элемент?». Hint (accessibilityHint в iOS, дополнительный текст в contentDescription в Android) — «Что произойдёт при взаимодействии?». VoiceOver произносит их последовательно: сначала Label, затем Hint.

Пример для кнопки удаления:

  • Label: «Удалить»
  • Hint: «Безвозвратно удалит выбранное фото»
  • VoiceOver: «Удалить. Безвозвратно удалит выбранное фото»

По данным Deque University, 2024, правильное разделение Label и Hint повышает успешность task completion rate для пользователей VoiceOver на 28%. Пользователи с когнитивными нарушениями особенно зависимы от Hint: рискуя нажать «Удалить» без пояснения, 40% отказываются от действия.

Когда Hint не нужен

  • Элемент с интуитивно понятным действием («Назад», «Закрыть» — Label достаточно)
  • Label уже описывает результат («Отправить сообщение» — глагол в самом имени)
  • Системные контролы (UISwitch, UIButton с системным типом) — их поведение стандартно

Ошибки из практики: Label вместо Hint

Частая ошибка: в Label пишут «Кнопка удаления» вместо «Удалить». Тип элемента (Button) добавляется VoiceOver автоматически через трейт. В результате пользователь слышит: «Кнопка удаления, кнопка» — дублирование. Правильный Label: «Удалить», Hint: «Удалит выбранное фото».

Локализация и лучшие практики

Локализация меток обязательна — она идёт через стандартные механизмы: NSLocalizedString в iOS, строковые ресурсы @string/ в Android. Никогда не задавайте Label конкатенацией на английском без локализации.

Правила хорошего Label, основанные на W3C WCAG 2.2:

  • Начинайте с ключевого слова — «Поиск товаров», а не «Поле для поиска товаров»
  • Не включайте слово «кнопка», «поле», «изображение» — роль добавляется автоматически
  • Используйте естественный язык, понятный целевой аудитории
  • Избегайте сокращений (кроме общепринятых: «шт.», «кг.») — screen reader читает их буквально
  • Для элементов ввода добавляйте пример: «Email (example@domain.com)»

Консистентность Label в рамках бренда

Используйте единый глоссарий для Label в приложении. Если на одном экране написано «Избранное», а на другом «Закладки», пользователь дезориентирован. Заведите Accessibility-таблицу терминов — согласуйте с дизайнерами и локализаторами.

Label для элементов форм

Для полей ввода (UITextField, EditText) Label должен совпадать с placeholder или заголовком поля. Однако placeholder часто скрывается после ввода текста. Используйте accessibilityLabel для постоянного имени и accessibilityValue для текущего содержимого поля — это стандарт WCAG 4.1.2. Решение: задайте accessibilityLabel статически (равным заголовку поля), а accessibilityValue — динамически (равным введённому тексту). В iOS это автоматически, но для кастомных полей — вручную через переопределение accessibilityValue. Проверьте, что VoiceOver читает: «Email, example@domain.com, текстовое поле» вместо «, текстовое поле».

Как тестировать метки доступности

Автоматизированное тестирование — единственный способ гарантировать корректность Label на всех экранах. iOS предоставляет XCUIApplication с доступом к .label, Android — AccessibilityCheckRule и setContentDescription.

Пример теста для iOS:

swift
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:

kotlin
@Test
fun testButtonHasAccessibilityLabel() {
    onView(withId(R.id.btnSubmit))
        .check(matches(
            withContentDescription(containsString("Отправить"))
        ))
}

Ручное тестирование: включите VoiceOver (iOS) или TalkBack (Android) и пройдите жестом вправо по всем элементам экрана. Каждый элемент должен получить осмысленное объявление. Если слышите только «кнопка» или «изображение» — Label отсутствует.

VoiceOver-ротор и быстрая навигация

После настройки Label пользователь VoiceOver может использовать ротор для быстрой навигации: режимы «Кнопки», «Заголовки», «Ссылки» и другие. Если Label задан правильно, VoiceOver включает элемент в соответствующий режим ротора. Проверьте, что все кнопки видны в режиме «Кнопки», все заголовки — в «Заголовки».

Label также влияет на поиск VoiceOver. Пользователь может ввести слово в поисковом режиме, и VoiceOver переместит фокус на элемент с подходящим Label. Поэтому в Label должны быть ключевые слова, по которым пользователь будет искать элемент.

Интеграция в CI/CD пайплайн

Добавьте проверку Label в pipeline. На iOS используйте XCUITest с fastlane scan. На Android — Accessibility Test Framework с правилом AccessibilityCheckRule, которое детектирует пустые contentDescription. Это предотвращает регрессии при мерже новых экранов.

Часто задаваемые вопросы

Чем Accessibility Label отличается от Accessibility Hint?

Label идентифицирует элемент («Поиск»), Hint поясняет результат действия («Откроет экран поиска»). VoiceOver произносит Label сразу при фокусе, а Hint — в режиме подробных описаний.

Нужно ли задавать Label для UILabel с текстом?

В iOS UILabel автоматически получает accessibilityLabel, равный своему тексту. Дополнительно задавать не нужно. В Android TextView ведёт себя аналогично.

Как задать Label для кастомного UIView?

Установите isAccessibilityElement = true на родительской View и переопределите accessibilityLabel, вернув конкатенированный текст из дочерних элементов. Для сложных компонентов используйте объединение с разделителем.

Как избежать дублирования Label на экране?

Добавляйте контекст к повторяющимся элементам: «Купить iPhone 15», «Купить iPhone 15 Pro». Автоматизируйте проверку через UI-тесты — собирайте все Label и проверяйте отсутствие дубликатов.

Можно ли использовать Label для скрытия элемента от screen reader?

Нет. Для скрытия элемента используйте isAccessibilityElement = false в iOS или importantForAccessibility = "no" в Android. Пустой Label не скрывает элемент — screen reader прочитает «без названия».

Итоги

  • Accessibility Label — имя элемента для VoiceOver и TalkBack; задаётся через accessibilityLabel в iOS и contentDescription в Android
  • Label должен совпадать с видимым текстом текстовых элементов; для нетекстовых (иконки, изображения) задаётся вручную
  • Hint отвечает на вопрос «Что произойдёт?» и не дублирует Label — у этих свойств разные роли
  • Каждый Label обязан быть уникальным на экране; дублирование дезориентирует пользователя screen reader
  • Локализация меток обязательна через NSLocalizedString (iOS) и @string (Android)
  • Тестируйте Label автоматически через UI-тесты (XCUIApplication, AccessibilityCheckRule) и вручную через VoiceOver
  • Декоративные элементы скрывайте через isAccessibilityElement = false или importantForAccessibility = "no"

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также