Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Клавиатурная доступность (Keyboard Accessibility)
Что такое клавиатурная доступность
Клавиатурная доступность — это возможность полного взаимодействия с веб-приложением, используя только клавиатуру без мыши. Это критично для пользователей с нарушениями моторики, слепоту или слабое зрение, а также для людей с моторными заболеваниями.
1. Фокусируемые элементы
Только определённые элементы могут получать фокус:
<button>,<a>,<input>,<select>,<textarea>- Пользовательские компоненты с
tabindex="0"
// Хорошо: кнопка по умолчанию фокусируемая
<button onClick={handleClick}>Нажми</button>
// Плохо: div не может получить фокус
<div onClick={handleClick}>Нажми</div>
// Хорошо: добавляем фокусируемость custom компоненту
<div tabIndex={0} role="button" onClick={handleClick}>
Кастомная кнопка
</div>
2. Порядок табуляции (Tab Order)
Tab order — это последовательность, в которой элементы получают фокус при нажатии Tab:
// Правильный порядок (слева направо, сверху вниз)
<form>
<input placeholder="Имя" /> {/* tabindex: 1 */}
<input placeholder="Email" /> {/* tabindex: 2 */}
<button type="submit">Отправить</button> {/* tabindex: 3 */}
</form>
// Избегаем явного tabindex (кроме 0 или -1)
// ❌ Не делай так:
<button tabIndex={5}>Кнопка</button>
3. Видимый фокус
Всегда должно быть видно, какой элемент имеет фокус:
/* CSS для видимого фокуса */
button:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
/* Удалять outline НЕ СЛЕДУЕТ без замены */
/* ❌ Не делай так: */
button:focus {
outline: none; /* потеря доступности */
}
/* ✅ Правильно: */
button:focus {
outline: 2px solid transparent;
outline-offset: 2px;
box-shadow: 0 0 0 2px white, 0 0 0 4px #0066cc;
}
4. Обработка клавиатурных событий
function CustomButton({ onClick, onKeyDown }) {
const handleKeyDown = (e) => {
// Enter или Space активирует кнопку
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick?.();
}
};
return (
<div
role="button"
tabIndex={0}
onClick={onClick}
onKeyDown={handleKeyDown}
aria-pressed="false"
>
Кастомная кнопка
</div>
);
}
5. ARIA атрибуты для управления
// Обозначь тип элемента
<div role="button">Клик</div>
// Состояние элемента
<button aria-pressed={isActive}>Toggle</button>
// Расширяемые элементы
<button aria-expanded={isOpen}>Меню</button>
// Скрытые элементы
<div aria-hidden="true">Декоративный элемент</div>
// Описание
<input aria-label="Поиск по сайту" />
6. Модальные диалоги
Элементы вне модали должны быть неактивны:
function Modal({ isOpen, children }) {
return (
<div role="dialog" aria-modal="true">
{children}
</div>
);
}
7. Пропуск навигации (Skip Links)
function SkipLink() {
return (
<a href="#main-content" className="sr-only">
Перейти к основному контенту
</a>
);
}
/* CSS для скрытия визуально, но видимо для экранных читателей */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
8. Тестирование
// Тест доступности с клавиатуры
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("кнопка активируется при нажатии Enter", async () => {
const user = userEvent.setup();
const handleClick = vi.fn();
render(<button onClick={handleClick}>Клик</button>);
const button = screen.getByRole("button");
button.focus();
await user.keyboard("{Enter}");
expect(handleClick).toHaveBeenCalled();
});
Итоги
Для полной клавиатурной доступности:
- Используй семантичные HTML элементы
- Обеспечь видимый фокус
- Правильно обрабатывай клавиатурные события (Enter, Space)
- Добавляй ARIA для пользовательских компонентов
- Тестируй только с клавиатурой