Короткий и практичный чек-лист для доступных веб-кнопок
Пять правил, которые помогают поймать большинство проблем доступности кнопок до продакшена
Содержание
- Проблема с советами по доступности кнопок
- 1. Используйте элемент button для кнопок
- 2. Делайте целевую область нажатия не меньше 44×44 пикселей
- 3. Обеспечьте видимые состояния фокуса, а не только браузерные значения по умолчанию
- 4. Пишите подписи кнопок, понятные вне контекста
- 5. Обеспечьте достаточный цветовой контраст
- Что этот чек-лист не охватывает
- Как встроить это в рабочий процесс
- Цена отказа от этой работы
- Ключевые выводы
- FAQ
- Sources
Проблема с советами по доступности кнопок
Большинство рекомендаций по доступности кнопок попадает в одну из двух категорий: либо это 40-страничная интерпретация WCAG, которую никто не читает, либо расплывчатый совет «сделайте кнопки доступными» без конкретных шагов. Ни то ни другое не помогает, когда нужно выпустить функцию в четверг.
Этот чек-лист охватывает пять самых частых ошибок доступности кнопок, которые мы видим в продакшене. Он не сделает вас экспертом по WCAG, но поможет поймать проблемы, которые действительно влияют на пользователей.
1. Используйте элемент button для кнопок
Если элемент ведет себя как кнопка, это должен быть элемент <button>. Не <div> с onclick, не <span> с role="button", не <a> с href="#" и preventDefault.
Элемент <button> дает вам клавиатурную навигацию, управление фокусом и озвучивание скринридером без дополнительной работы. Когда вы используете <div>, вы заново собираете все это с нуля — и почти наверняка ошибетесь.
Единственное исключение: если действие ведет на новую страницу или меняет URL, используйте элемент <a>. Ссылки и кнопки семантически различаются. Пользователи скринридеров перемещаются по типам элементов, и они ожидают, что кнопки выполняют действия, а ссылки — осуществляют навигацию.
2. Делайте целевую область нажатия не меньше 44×44 пикселей
WCAG 2.5.5 (Level AAA) требует, чтобы интерактивные элементы имели минимальный размер целевой области 44×44 CSS-пикселя. Речь не о визуальном размере — речь о кликабельной области.
У вас может быть маленькая визуальная кнопка с достаточными внутренними отступами, или вы можете расширить целевую область с помощью псевдоэлемента. Важно, чтобы пользователю не приходилось попадать идеально точно.
Пользователи мобильных устройств, люди с моторными нарушениями и все, кто пользуется устройством в движении, будут промахиваться по маленьким целям. Иконка-кнопка размером 24×24 пикселя может выглядеть аккуратно, но с точки зрения удобства это ошибка.
3. Обеспечьте видимые состояния фокуса, а не только браузерные значения по умолчанию
Стандартное кольцо фокуса в браузере лучше, чем ничего, но оно отличается в разных браузерах и часто незаметно на некоторых фонах. Вам нужно собственное состояние фокуса, которое работает в вашей дизайн-системе.
У хорошего индикатора фокуса есть три качества:
- Высокий контраст: не менее 3:1 по отношению к соседним цветам
- Видимый отступ: индикатор не скрывается собственной рамкой или фоном кнопки
- Единая форма: пользователи должны узнавать его как индикатор фокуса во всем интерфейсе
Не удаляйте outline: none, если не заменяете его чем-то лучшим. И не делайте состояния фокуса настолько тонкими, что их видите только вы при идеальном освещении.
4. Пишите подписи кнопок, понятные вне контекста
Пользователи скринридеров часто перемещаются, переходя от кнопки к кнопке. В этот момент они слышат список подписей кнопок без окружающего контекста.
Кнопка с подписью «Узнать больше» в таком списке бесполезна. То же касается «Нажмите здесь» или «Отправить». Подпись должна описывать действие: «Скачать чек-лист по доступности», «Подписаться на обновления», «Удалить этот комментарий».
Если дизайн требует короткой визуальной подписи, используйте aria-label, чтобы дать описательную альтернативу. Но лучшее решение — писать подписи, которые работают для всех.
Для кнопок только с иконкой aria-label обязателен. Кнопке с одной лишь иконкой лупы нужен aria-label="Search" или эквивалентный текст. Иконка недоступна для скринридеров.
5. Обеспечьте достаточный цветовой контраст
WCAG 2.1 требует коэффициент контрастности не менее 4.5:1 для обычного текста и 3:1 для крупного текста (18pt или 14pt bold). Подписи кнопок обычно относятся к обычному тексту.
Светло-серый текст на белой кнопке не проходит проверку. Бледно-синий на светло-синем фоне тоже не проходит. Такие сочетания могут выглядеть изысканно, но они исключают пользователей со слабым зрением, дальтонизмом или любого, кто смотрит на экран при ярком солнечном свете.
Используйте проверку контраста на этапе дизайна, а не после запуска. Исправлять проблемы контраста в продакшене дорого, потому что это часто требует изменений в дизайн-системе.
Если вы работаете с инструментами обработки изображений, обработка на стороне клиента может помочь сохранить приватность при создании доступных визуальных материалов — особенно при тестировании цветовых сочетаний или создании состояний предпросмотра.
Что этот чек-лист не охватывает
Этот список намеренно неполный. Он не рассматривает семантику отключенного состояния, состояния загрузки, обработку ошибок или сложные паттерны кнопок вроде split buttons или dropdown triggers. Для таких паттернов нужны отдельные рекомендации.
Он также не рассматривает более широкий вопрос о том, когда использовать кнопку вместо других интерактивных элементов. Для этого нужно понимать семантический HTML и дерево доступности — темы, заслуживающие отдельных статей.
Зато он охватывает самые простые и заметные улучшения: ошибки, которые встречаются почти на каждом code review, влияют на большинство пользователей и проще всего исправляются во время разработки.
Как встроить это в рабочий процесс
Чек-листы доступности работают только тогда, когда они являются частью процесса разработки, а не прикручиваются постфактум. Вот как этого добиться:
В дизайне: добавляйте состояния фокуса и аннотации целевых областей нажатия в дизайн-файлы. Не оставляйте разработчикам необходимость угадывать.
На code review: проверяйте элементы <button>, aria-label у кнопок с иконками и CSS для состояний фокуса. Это быстро заметить.
В тестировании: пройдите по интерфейсу с клавиатуры с помощью Tab. Если вы не можете добраться до кнопки или не видите, где находится фокус, ваши пользователи тоже не смогут.
В документации: включите требования к доступности кнопок в библиотеку компонентов. Сделайте правильное действие проще неправильного.
Если вы отлаживаете проблемы в продакшене, инструменты для проверки HTTP-заголовков и редиректов могут помочь понять, как ассистивные технологии интерпретируют вашу разметку — особенно при поиске проблем с управлением фокусом после навигации.
Цена отказа от этой работы
Недоступные кнопки не просто нарушают соответствие WCAG — они ломают пользовательские сценарии. Пользователь, который не может нажать кнопку отправки, не может заполнить форму. Пользователь, который не видит состояния фокуса, не может перемещаться с клавиатуры. Пользователь, который не может отличить текст кнопки от фона, не может прочитать подпись.
Это не пограничные случаи. Около 15% населения мира имеет ту или иную форму инвалидности, а временные ограничения (сломанная мышь, яркое солнце, ребенок на руках) рано или поздно затрагивают всех.
Хорошая новость в том, что доступность кнопок в основном состоит из уже решенных задач. Вам не нужно изобретать новые паттерны или ждать поддержки браузеров. Нужно просто правильно использовать платформу и тестировать свою работу.
Ключевые выводы
- Используйте элементы
<button>для кнопок и элементы<a>для навигации — семантическая разница важна для ассистивных технологий - Обеспечьте целевые области нажатия не менее 44×44 CSS-пикселей, чтобы учесть моторные нарушения и пользователей мобильных устройств
- Делайте видимые, высококонтрастные состояния фокуса, которые работают во всей дизайн-системе
- Пишите подписи кнопок, понятные при чтении отдельно, и используйте
aria-labelдля кнопок только с иконкой - Проверяйте цветовой контраст на этапе дизайна, а не после запуска, чтобы избежать дорогих доработок
FAQ
Q: Можно ли использовать role="button" на <div>, если добавить обработчики клавиатуры?
A: Можно, но не стоит. Вам придется вручную обработать Enter, Space, управление фокусом и отключенные состояния — и вы неизбежно что-то упустите. Элемент <button> делает все это корректно по умолчанию. Используйте его.
Q: Что насчет кнопок, которые переключают состояние, например play/pause?
A: Используйте aria-pressed="true" или aria-pressed="false", чтобы указать текущее состояние. Подпись кнопки также должна отражать действие, которое произойдет при нажатии («Пауза», когда воспроизведение идет, «Воспроизвести», когда оно приостановлено), а не текущее состояние. Пользователям скринридеров нужно знать, что сделает кнопка, а не в каком состоянии находится система.
Q: Должны ли отключенные кнопки соответствовать требованиям контрастности?
A: WCAG 2.1 освобождает отключенные элементы управления от требований к контрастности (1.4.3), но это спорный момент. Отключенные кнопки с плохим контрастом трудно воспринимать всем. Если вы показываете отключенную кнопку, сделайте ее читаемой. А еще лучше — скройте ее или объясните, почему она отключена.
Q: Как тестировать доступность кнопок без скринридера?
A: Используйте клавиатуру. Пройдите по интерфейсу клавишей Tab и убедитесь, что можете добраться до каждой кнопки, видите, где находится фокус, и можете активировать кнопки с помощью Enter или Space. Это выявляет большинство проблем. Для более глубокой проверки используйте инспектор доступности в Chrome или Firefox DevTools, чтобы проверить вычисленные роль и подпись.
Q: В чем разница между aria-label и aria-labelledby?
A: aria-label задает текстовую строку напрямую. aria-labelledby ссылается на ID другого элемента, текстовое содержимое которого становится подписью. Используйте aria-labelledby, когда текст подписи уже существует в DOM. Используйте aria-label, когда нужно предоставить подпись, не видимую на экране.
Sources
- Web Content Accessibility Guidelines (WCAG) 2.1 — W3C
- Inclusive Components: Toggle Buttons — Heydon Pickering
- The ARIA Button Pattern — W3C ARIA Authoring Practices Guide
- WebAIM: Keyboard Accessibility — WebAIM


