Услуги
Заказы
Эксперты
Магазин
Портфолио
Журнал
Справочник
FAQ
Контакты
Услуги
Заказы
Эксперты
Магазин
Портфолио
Журнал
Справочник
Вопросы
FAQ
Контакты
Авторизация
Ничего не найдено
Найти
На примере JavaScript/HTML объясните, как обеспечить доступность (accessibility) интерактивного компонента (например, кастомного селекта) для пользователей с ограничениями
Предыдущий
вопрос
Следующий
вопрос
Главная
Вопросы и ответы
Вопросы и ответы по программированию
На примере JavaScrip...
Ответить
Получить ответ за 25 ₽
Задать свой вопрос
eva
26 Мая в 10:19
20
+1
0
Ответы
1
Helper
Helper
Ключевые моменты для доступного кастомного селекта: семантика ARIA, полная клавиатурная навигация, управления фокусом, синхронизация со встроенным для отправки формы, видимые фокус/контраст и тестирование со считывателями экрана. Ниже — компактный пример (HTML + JS) и пояснения.
Пример (вставьте в HTML-файл):
HTML:
```html
Страна<button
id="select-button"
aria-haspopup="listbox"
aria-expanded="false"
aria-labelledby="country-label select-button"
>
Выберите...
▾
United StatesCanadaMexico...United StatesCanadaMexico ```
JavaScript:
```javascript
const button = document.getElementById('select-button');
const listbox = document.getElementById('listbox');
const options = Array.from(listbox.querySelectorAll('[role="option"]'));
const selectedSpan = document.getElementById('selected-value');
const native = document.getElementById('native-select');
let open = false;
let activeIndex = -1;
function openList(focusIndex = 0) {
open = true;
button.setAttribute('aria-expanded', 'true');
listbox.hidden = false;
listbox.focus();
setActive(focusIndex);
}
function closeList(commit = false) {
open = false;
button.setAttribute('aria-expanded', 'false');
listbox.hidden = true;
clearActive();
button.focus();
}
function setActive(index) {
if (activeIndex >= 0) options[activeIndex].setAttribute('aria-selected', 'false');
activeIndex = Math.max(0, Math.min(index, options.length - 1));
const opt = options[activeIndex];
opt.setAttribute('aria-selected', 'true');
// прокрутка в видимую область:
opt.scrollIntoView({ block: 'nearest' });
// Обновить aria-activedescendant на listbox (опционально)
listbox.setAttribute('aria-activedescendant',
opt.id
);
}
function clearActive() {
if (activeIndex >= 0) options[activeIndex].setAttribute('aria-selected', 'false');
activeIndex = -1;
listbox.removeAttribute('aria-activedescendant');
}
function commitSelection() {
if (activeIndex < 0) return;
const opt = options[activeIndex];
const value = opt.dataset.value;
selectedSpan.textContent = opt.textContent;
// синхронизировать скрытый native select
native.value = value;
// при необходимости — генерировать change
native.dispatchEvent(new Event('change', { bubbles: true }));
}
button.addEventListener('click', (e) => {
e.preventDefault();
if (open) closeList();
else openList();
});
button.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') { e.preventDefault(); openList(0); }
if (e.key === 'ArrowUp') { e.preventDefault(); openList(options.length - 1); }
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openList(); }
});
listbox.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') { e.preventDefault(); setActive(activeIndex + 1); }
else if (e.key === 'ArrowUp') { e.preventDefault(); setActive(activeIndex - 1); }
else if (e.key === 'Home') { e.preventDefault(); setActive(0); }
else if (e.key === 'End') { e.preventDefault(); setActive(options.length - 1); }
else if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); commitSelection(); closeList(true); }
else if (e.key === 'Escape') { e.preventDefault(); closeList(); }
// можно добавить typeahead (по нажатиям букв) для поиска
});
options.forEach((opt, i) => {
opt.addEventListener('click', (e) => {
activeIndex = i;
commitSelection();
closeList(true);
});
// фокусируем элемент при наведении (опционально, улучшает мышечную доступность)
opt.addEventListener('mouseenter', () => setActive(i));
});
```
Ключевые пояснения (коротко):
- Семантика: используйте role="listbox" и role="option" или role="combobox" по шаблонам ARIA; обязательно aria-expanded/aria-haspopup на контроле.
- Клавиатура: поддержка Enter/Space (выбор/открытие), ArrowUp/Down навигация, Home/End, Escape. Поддержите типовой набор, ожидаемый пользователями.
- Фокус: при открытии переводите фокус в список (или держите его на контроле и используйте aria-activedescendant). Обязательно видимая индикаторная рамка (outline).
- Состояния: использовать aria-selected для опций, aria-expanded для кнопки, aria-activedescendant для указания активной опции.
- Формы: синхронизация со скрытым нативным (или input) чтобы данные отправлялись и чтобы формы работали без JS при возможности.
- Скринридеры: тестируйте NVDA, JAWS, VoiceOver; используйте короткие метки (aria-labelledby/aria-label).
- Дополнительно: контраст, размер клика (минимум 44px рекомендуют), избегайте незаметного скрытия опций для assistive tech (используйте hidden + aria-hidden корректно).
Тестируйте: только клавиатура, экранный считыватель, увеличенные шрифты и мобильные вспомогательные технологии. Это обеспечит, что кастомный компонент удобен для пользователей с различными ограничениями.
Ответить
26 Мая в 10:50
Спасибо
Похожие вопросы
Почему следующий Rust-код не компилируется: fn main() { let mut v = Vec::new(); let x = &v; v.push(1); println!("{:?}",…
eva
Программирование
20 Окт
1
Ответить
Как вы бы действовали технически и организационно, если обнаружили, что модель машинного обучения в продукте…
eva
Программирование
20 Окт
1
Ответить
Опишите, как применять property-based тестирование (например, QuickCheck) для проверки реализации функции…
eva
Программирование
20 Окт
1
Ответить
Показать ещё
Другие вопросы
eva
Показать ещё
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Тип работы
Задача
Контрольная
Курсовая
Лабораторная
Дипломная
Реферат
Практика
Тест
Чертеж
Сочинение
Эссе
Перевод
Диссертация
Бизнес-план
Презентация
Билеты
Статья
Доклад
Онлайн-помощь
Рецензия
Монография
ВКР
РГР
Маркетинговое исследование
Автореферат
Аннотация
НИР
Докторская диссертация
Магистерская диссертация
Кандидатская диссертация
ВАК
Scopus
РИНЦ
Шпаргалка
Дистанционная задача
Творческая работа
Разместить заказ
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Задача
Контрольная работа
Курсовая работа
Лабораторная работа
Дипломная работа
Реферат
Отчет по практике
Тест
Чертеж
Сочинение
Эссе
Перевод
Диссертация
Бизнес-план
Презентация
Ответы на билеты
Статья
Доклад
Онлайн-помощь
Рецензия
Монография
ВКР
РГР
Маркетинговое исследование
Автореферат
Аннотация
НИР
Докторская диссертация
Магистерская диссертация
Кандидатская диссертация
ВАК
Scopus
РИНЦ
Шпаргалка
Дистанционная задача
Творческая работа
Заказать
Прямой эфир
Пример (вставьте в HTML-файл):
HTML:
```html
Страна<button
id="select-button"
aria-haspopup="listbox"
aria-expanded="false"
aria-labelledby="country-label select-button"
>Выберите...▾United StatesCanadaMexico...United StatesCanadaMexico ```
JavaScript:
```javascript
const button = document.getElementById('select-button');
const listbox = document.getElementById('listbox');
const options = Array.from(listbox.querySelectorAll('[role="option"]'));
const selectedSpan = document.getElementById('selected-value');
const native = document.getElementById('native-select');
let open = false;
let activeIndex = -1;
function openList(focusIndex = 0) {
open = true;
button.setAttribute('aria-expanded', 'true');
listbox.hidden = false;
listbox.focus();
setActive(focusIndex);
}
function closeList(commit = false) {
open = false;
button.setAttribute('aria-expanded', 'false');
listbox.hidden = true;
clearActive();
button.focus();
}
function setActive(index) {
if (activeIndex >= 0) options[activeIndex].setAttribute('aria-selected', 'false');
activeIndex = Math.max(0, Math.min(index, options.length - 1));
const opt = options[activeIndex];
opt.setAttribute('aria-selected', 'true');
// прокрутка в видимую область:
opt.scrollIntoView({ block: 'nearest' });
// Обновить aria-activedescendant на listbox (опционально)
listbox.setAttribute('aria-activedescendant', opt.id);
}
function clearActive() {
if (activeIndex >= 0) options[activeIndex].setAttribute('aria-selected', 'false');
activeIndex = -1;
listbox.removeAttribute('aria-activedescendant');
}
function commitSelection() {
if (activeIndex < 0) return;
const opt = options[activeIndex];
const value = opt.dataset.value;
selectedSpan.textContent = opt.textContent;
// синхронизировать скрытый native select
native.value = value;
// при необходимости — генерировать change
native.dispatchEvent(new Event('change', { bubbles: true }));
}
button.addEventListener('click', (e) => {
e.preventDefault();
if (open) closeList();
else openList();
});
button.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') { e.preventDefault(); openList(0); }
if (e.key === 'ArrowUp') { e.preventDefault(); openList(options.length - 1); }
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openList(); }
});
listbox.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') { e.preventDefault(); setActive(activeIndex + 1); }
else if (e.key === 'ArrowUp') { e.preventDefault(); setActive(activeIndex - 1); }
else if (e.key === 'Home') { e.preventDefault(); setActive(0); }
else if (e.key === 'End') { e.preventDefault(); setActive(options.length - 1); }
else if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); commitSelection(); closeList(true); }
else if (e.key === 'Escape') { e.preventDefault(); closeList(); }
// можно добавить typeahead (по нажатиям букв) для поиска
});
options.forEach((opt, i) => {
opt.addEventListener('click', (e) => {
activeIndex = i;
commitSelection();
closeList(true);
});
// фокусируем элемент при наведении (опционально, улучшает мышечную доступность)
opt.addEventListener('mouseenter', () => setActive(i));
});
```
Ключевые пояснения (коротко):
- Семантика: используйте role="listbox" и role="option" или role="combobox" по шаблонам ARIA; обязательно aria-expanded/aria-haspopup на контроле.
- Клавиатура: поддержка Enter/Space (выбор/открытие), ArrowUp/Down навигация, Home/End, Escape. Поддержите типовой набор, ожидаемый пользователями.
- Фокус: при открытии переводите фокус в список (или держите его на контроле и используйте aria-activedescendant). Обязательно видимая индикаторная рамка (outline).
- Состояния: использовать aria-selected для опций, aria-expanded для кнопки, aria-activedescendant для указания активной опции.
- Формы: синхронизация со скрытым нативным (или input) чтобы данные отправлялись и чтобы формы работали без JS при возможности.
- Скринридеры: тестируйте NVDA, JAWS, VoiceOver; используйте короткие метки (aria-labelledby/aria-label).
- Дополнительно: контраст, размер клика (минимум 44px рекомендуют), избегайте незаметного скрытия опций для assistive tech (используйте hidden + aria-hidden корректно).
Тестируйте: только клавиатура, экранный считыватель, увеличенные шрифты и мобильные вспомогательные технологии. Это обеспечит, что кастомный компонент удобен для пользователей с различными ограничениями.