Использование Javascript для улучшения доступности форм с помощью Aria Labels

Почему важно формировать доступность

Веб-формы являются одними из наиболее распространенных и важных компонентов цифрового опыта. Они обеспечивают работу страниц входа в систему, потоков оформления заказа, представлений опросов, запросов на контакт и бесчисленных других взаимодействий. Для пользователей с визуальными, двигательными или когнитивными нарушениями плохо построенная форма может быть непреодолимым барьером. Доступность - обеспечение того, что все пользователи могут воспринимать, понимать, ориентироваться и взаимодействовать с формами - это не просто этические обязательства; это юридическое требование во многих юрисдикциях и практическое преимущество бизнеса, которое расширяет охват аудитории и снижает затраты на поддержку.

Вспомогательные технологии, такие как устройства чтения экрана, программное обеспечение распознавания голоса и коммутаторы, полагаются на хорошо структурированный семантический HTML и правильно применяемые атрибуты ARIA (Доступные богатые интернет-приложения), чтобы передать элементы управления формой, их цели и текущие состояния. Без этих сигналов пользователи могут столкнуться с отсутствующими или запутанными ярлыками, не знать о необходимых полях, не понимать ошибки проверки или быть неспособными завершить представления.

В этой статье рассматривается, как JavaScript может быть использован для повышения доступности форм посредством динамического применения и управления метками ARIA. Мы рассмотрим основные атрибуты ARIA для форм, пройдемся по реальным шаблонам JavaScript для улучшения ясности метки, связи с ошибками и обновлений живой области и предоставим примеры кода, которые можно адаптировать немедленно. К концу вы поймете, как сочетать методы JavaScript с ARIA для создания форм, которые являются надежными, реактивными и инклюзивными.

Понимание ярлыков ARIA и их роли в формах

ARIA предоставляет набор атрибутов, которые дополняют HTML для улучшения доступности динамического контента и сложных элементов управления пользовательским интерфейсом. Для форм наиболее важными атрибутами являются:

Эти атрибуты не меняют визуального облика формы; они влияют только на то, как вспомогательные технологии интерпретируют и объявляют элементы.Правильное их использование является краеугольным камнем доступного дизайна формы.

Когда нативного HTML недостаточно: необходимость в JavaScript

Только HTML может создавать доступные формы: используя элементы с атрибутами , , и для группировки, и нативную валидацию с и .

  • Формы, которые построены или изменены на стороне клиента (например, одностраничные приложения).
  • Условные поля, которые появляются или исчезают на основе выбора пользователя.
  • Пользовательские элементы формы (например, пользовательские галочки, выберите коробки), которые теряют нативную доступность.
  • Обратная связь проверки в реальном времени, которая обновляет сообщения об ошибках без перезагрузки страницы.
  • Многошаговые или волшебные формы, в которых необходимо управлять фокусом и анонсировать изменения контекста.

JavaScript устраняет эти пробелы, программно назначая, обновляя и удаляя атрибуты ARIA, поскольку пользователь взаимодействует с интерфейсом. Это гарантирует, что пользователи вспомогательных технологий получают ту же информацию и сигналы, что и зрячие пользователи.

Основные шаблоны: использование JavaScript для добавления и обновления ярлыков ARIA

Шаблон 1: Присвоение вводимым данным без видимых ярлыков

Иногда ограничения визуального дизайна означают, что маркировка ввода видимым текстом непрактична. В этих случаях предоставляет доступное имя. Простейший подход заключается в том, чтобы добавить его непосредственно в HTML, но когда форма генерируется динамически компонентами JavaScript или извлекается из API, вы можете вставить его после создания элемента.

// After a dynamic input is created or added to the DOM
const searchInput = document.querySelector('.search-field');
if (searchInput) {
 searchInput.setAttribute('aria-label', 'Search website');
}

Избегать дублирования информации: если видимая метка присутствует, но не связана с или вложении, рассмотрите возможность использования вместо этого, чтобы избежать избыточности. W3C ARIA Спецификация содержит рекомендации о том, когда каждый атрибут является подходящим.

Шаблон 2: Укрепление ассоциации с этикетками

Если группа элементов (например, радиокнопки) описывается видимым заголовком, вы можете ссылаться на этот заголовок из каждого управления. JavaScript может использоваться для сбора идентификатора заголовка и применения атрибута ко всем соответствующим входам.

const groupHeading = document.getElementById('shipping-options-heading');
if (groupHeading) {
 const radioButtons = document.querySelectorAll('input[name="shipping"]');
 radioButtons.forEach(radio => {
 radio.setAttribute('aria-labelledby', groupHeading.id);
 });
}

Это более надежно, чем использование , потому что он повторно использует существующий видимый контент, что выгодно пользователям, которые полагаются на пользовательские настройки текста или настройки вербозита считывателя экрана.

Паттерн 3: Объявления о динамических изменениях в реальном регионе

Когда содержимое формы изменяется без полной загрузки страницы, например, отображение поля кода скидки после тикания флажка, пользователи считывающего экрана могут не знать о новом контенте. Объединив области с JavaScript, вы можете объявить об этих изменениях.

const toggle = document.getElementById('promo-toggle');
const promoContainer = document.getElementById('promo-code-container');
promoContainer.setAttribute('aria-live', 'polite');

toggle.addEventListener('change', function () {
 if (this.checked) {
 promoContainer.classList.remove('hidden');
 promoContainer.innerHTML = `
 <label for="promo-code">Enter promo code</label>
 <input type="text" id="promo-code">
 `;
 document.getElementById('promo-code').setAttribute('aria-label', 'Promotion code');
 } else {
 promoContainer.classList.add('hidden');
 promoContainer.innerHTML = '';
 }
});

Обратите внимание, что регионы лучше всего подходят для простых объявлений; для большего контроля рассмотрите возможность использования выделенного элемента «живой» области, который вы обновляете вручную.

Динамическая валидация и коммуникация с ошибками

Одним из наиболее эффективных применений JavaScript в доступных формах является обработка ошибок проверки.WCAG Success Criterion 3.3.1 (Error Identification) требует, чтобы любая ошибка ввода была описана в тексте пользователю. атрибуты ARIA, такие как и , являются ключом к удовлетворению этого требования динамически.

[[28]] Ошибка в подтверждении

Когда поле формы не валидируется (либо нативное, либо пользовательское), установите и удалите его (или установите ), когда ошибка исправлена.

const emailInput = document.getElementById('email');

function validateEmail(value) {
 const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
 emailInput.setAttribute('aria-invalid', !isValid);
 return isValid;
}

emailInput.addEventListener('blur', function () {
 validateEmail(this.value);
});

Связывание сообщений об ошибках с и

Текст ошибки должен быть программно связан с полем. Используйте , чтобы указать на контейнер сообщения, или для более нового, более точного атрибута. Следующий пример создает промежуток ошибок и прикрепляет его к полю.

const emailInput = document.getElementById('email');
const errorContainer = document.getElementById('email-error');

emailInput.addEventListener('invalid', function (event) {
 event.preventDefault(); // prevent native popup
 this.setAttribute('aria-invalid', 'true');
 this.setAttribute('aria-describedby', 'email-error');
 errorContainer.textContent = 'Please enter a valid email address.';
 errorContainer.style.display = 'block';
});

emailInput.addEventListener('input', function () {
 if (this.validity.valid) {
 this.setAttribute('aria-invalid', 'false');
 this.removeAttribute('aria-describedby');
 errorContainer.textContent = '';
 errorContainer.style.display = 'none';
 }
});

Обратите внимание, что поддерживается в новых экранных считывателях, но остается более широко совместимой. Документация MDN обеспечивает тщательное сравнение.

Управление фокусом для инклюзивного потока

В многошаговых формах или при появлении ошибок управление фокусом имеет решающее значение. JavaScript может программно перемещать фокус в первое недействительное поле или в сводку ошибок. Всегда сообщайте причину перемещения фокуса с помощью области или заголовка.

function focusFirstError() {
 const firstError = document.querySelector('[aria-invalid="true"]');
 if (firstError) {
 firstError.focus();
 // Optionally announce
 const announcer = document.getElementById('form-feedback');
 announcer.textContent = 'The form contains errors. The first invalid field has been focused.';
 announcer.setAttribute('aria-live', 'assertive');
 }
}

document.getElementById('submit-btn').addEventListener('click', function (e) {
 if (!validateForm()) {
 e.preventDefault();
 focusFirstError();
 }
});

Будьте осторожны с ; используйте для некритических обновлений. Управление фокусом без объявления может сбить с толку пользователей, поскольку они могут не понимать, почему они были перемещены.

Обработка пользовательских форм контроля

Многие проекты используют флажки, радиокнопки, меню или переключатели переключения. Они теряют нативную семантику и требуют ролей ARIA, состояний и свойств, реализованных через JavaScript. Например, пользовательский флажок нуждается в , и слушателях событий на клавиатуре.

const customCheckbox = document.getElementById('custom-checkbox');

customCheckbox.setAttribute('role', 'checkbox');
customCheckbox.setAttribute('aria-checked', 'false');
customCheckbox.setAttribute('tabindex', '0');
customCheckbox.setAttribute('aria-label', 'Accept terms and conditions');

customCheckbox.addEventListener('click', function () {
 const isChecked = this.getAttribute('aria-checked') === 'true' ? false : true;
 this.setAttribute('aria-checked', isChecked);
 this.classList.toggle('checked', isChecked);
});

customCheckbox.addEventListener('keydown', function (e) {
 if (e.key === ' ' || e.key === 'Enter') {
 e.preventDefault();
 this.click();
 }
});

Хотя такие шаблоны возможны, предпочтите нативные элементы HTML, когда это возможно: они поставляются со встроенной доступностью, обработкой клавиатуры и минимальными накладными расходами JavaScript.

Лучшие практики использования JavaScript с ARIA

  • Начните с семантического HTML. Всегда начинайте с надлежащих ассоциаций и нативных входов перед наложением ARIA. ARIA должна исправить то, что HTML не может.
  • Сохраняйте атрибуты ARIA в актуальном состоянии. Убедитесь, что ваш JavaScript обновляет , и доступные имена в режиме реального времени, поскольку взаимодействия пользователей изменяют состояние формы.
  • Не переопределяйте родное поведение. Например, не дублируйте с на одном элементе, если вам не нужно поддерживать старые пользовательские агенты; вместо этого позвольте родному атрибуту выполнять работу и добавляйте ARIA только там, где это необходимо.
  • Испытания с реальными вспомогательными технологиями. Автоматизированные валидаторы улавливают только около 30% проблем с доступностью. Всегда тестируйте с помощью считывателей экрана (NVDA, VoiceOver, JAWS) и навигации только на клавиатуре.
  • По возможности, следует использовать видимые метки. Пользователи с когнитивными нарушениями получают выгоду от видимых меток. Скрытые метки (с использованием или ) следует использовать только тогда, когда дизайн действительно не может вместить видимый текст.
  • Использовать живые регионы разумно. Использование может перегрузить пользователей считывающего устройства. для рутинных обновлений и только для чувствительных ко времени объявлений (например, для успеха/неудачи подачи формы).

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

Ниже приведен краткий пример, который связывает несколько шаблонов: условные поля, динамические метки ARIA, обработка ошибок проверки и управление фокусом. Этот код готов к производству, но упрощен для ясности.

<form id="registration-form" novalidate>
 <label for="username">Username (required)</label>
 <input type="text" id="username" required>

 <label for="newsletter">Subscribe to newsletter</label>
 <input type="checkbox" id="newsletter">
 <div id="email-group" hidden>
 <label for="email">Email</label>
 <input type="email" id="email">
 </div>

 <button type="submit">Register</button>
 <div id="form-errors" aria-live="polite"></div>
</form>

<script>
 const newsletter = document.getElementById('newsletter');
 const emailGroup = document.getElementById('email-group');
 const emailInput = document.getElementById('email');
 const form = document.getElementById('registration-form');
 const errorDisplay = document.getElementById('form-errors');

 // Show email field only if newsletter is checked
 newsletter.addEventListener('change', function () {
 if (this.checked) {
 emailGroup.hidden = false;
 emailInput.setAttribute('aria-label', 'Email address for newsletter');
 emailInput.setAttribute('aria-required', 'true');
 emailInput.required = true;
 } else {
 emailGroup.hidden = true;
 emailInput.removeAttribute('aria-label');
 emailInput.removeAttribute('aria-required');
 emailInput.required = false;
 emailInput.value = '';
 }
 });

 // Client-side validation and error display
 form.addEventListener('submit', function (event) {
 event.preventDefault();
 let errors = [];
 const username = document.getElementById('username');
 if (!username.value.trim()) {
 username.setAttribute('aria-invalid', 'true');
 username.setAttribute('aria-describedby', 'form-errors');
 errors.push('Username is required.');
 } else {
 username.setAttribute('aria-invalid', 'false');
 username.removeAttribute('aria-describedby');
 }

 if (!emailGroup.hidden && !emailInput.value.trim()) {
 emailInput.setAttribute('aria-invalid', 'true');
 emailInput.setAttribute('aria-describedby', 'form-errors');
 errors.push('Email is required for newsletter subscription.');
 } else if (!emailGroup.hidden) {
 emailInput.setAttribute('aria-invalid', 'false');
 emailInput.removeAttribute('aria-describedby');
 }

 errorDisplay.textContent = errors.join(' ');

 if (errors.length > 0) {
 // Focus first error field
 const firstErrorField = document.querySelector('[aria-invalid="true"]');
 if (firstErrorField) firstErrorField.focus();
 } else {
 // Successful submission (would send data)
 errorDisplay.textContent = 'Registration successful!';
 errorDisplay.setAttribute('aria-live', 'assertive');
 }
 });
</script>

Этот пример демонстрирует, как JavaScript может динамически добавлять , когда появляется поле электронной почты, устанавливать условно, управлять и во время проверки и использовать область для суммирования ошибок.

Заключение

Доступные формы не являются роскошью - они являются фундаментальным требованием для справедливого цифрового доступа. Объединив атрибуты ARIA с JavaScript, разработчики могут создавать интерфейсы, которые реагируют на действия пользователей, сохраняя четкую, последовательную связь с вспомогательными технологиями. Модели, описанные в этой статье - динамическая маркировка, объявления в реальном регионе, связывание ошибок, управление фокусом и обработка пользовательского контроля - предоставляют практический инструментарий для любого веб-разработчика, работающего с интерактивными формами.

Всегда помните, что ARIA является дополнением, а не заменой. Начните с чистого семантического HTML, проверьте с помощью реальных вспомогательных технологий и итерируйте на основе обратной связи с пользователем. При использовании вдумчиво JavaScript и ARIA вместе могут превратить форму из источника разочарования в бесшовный, инклюзивный опыт. Для дальнейшего чтения обратитесь к WAI-ARIA Authoring Practices и WebAIM руководство по доступным формам .