Привет, Хабр! В предыдущей статье я рассказывал о простых случаях проблем с доступностью, исправив которые можно сделать свой сайт или web-приложение гораздо доступнее. Я упоминал о правиле 80/20 и писал о проблемах, которые при наименьших затратах дают наибольший результат. Сегодня я бы хотел поговорить о другой группе проблем, которые входят в 20% и для решения которых нет готовых рецептов вроде всегда заполняйте атрибут alt или используйте верные заголовки.
Выбирая формат повествования, я не придумал ничего лучше, чем просто описать ход своих мыслей на достаточно часто встречающемся примере.
Формализуем проблему
Как я уже говорил, для некоторых проблем в сфере доступности невозможно предложить какое-то простое решение. Эти проблемы очень вариативны, а иногда и вовсе уникальны для конкретного приложения. Помимо этого, ситуация осложняется различиями в работе разных скринридеров в разных браузерах и на разных операционных системах. Дополняет всё это то, что решение лежит на стыке двух дисциплин: доступности с её стандартами и
Interaction Design
(Проектирование
взаимодействия) с её достаточно гибкими правилами.Если вы, как и я в такие моменты, чувствуете уныние, то предлагаю не решать все проблемы сразу, а двигаться постепенно.
Обычно я начинаю с описания алгоритма взаимодействия с моим элементом для пользователей без мышки. Пользователи клавиатуры это большая группа пользователей, далеко не всегда с какими-то ограничениями. Иногда это просто люди, которые ценят скорость работы.
Почти все сложные проблемы с доступностью возникают на элементах, которые динамически изменяют контент после какого-то действия пользователя.
К таким элементам можно отнести:
- табы;
- модальные окна;
- аккордеон;
- меню (в том числе с большой вложенностью).
Каждый компонент их этого списка можно условно разделить на две составляющие:
- триггер элемент, запускающий действие;
- целевой контент элемент, который содержит в себе кусочек видоизмененного контента.
Реализация триггера
Первое, с чем я предлагаю разобраться, это какой базовый элемент будет лежать в основе триггера. Использование элементов, которые сразу являются фокусируемыми и интерактивными, я считаю хорошей идеей. Поэтому сразу отбрасываю всевозможные реализации с помощью
div
, span
и т. д.В итоге я прихожу к первому вопросу: должен ли быть триггер ссылкой или кнопкой?
Ответ на этот вопрос звучит примерно так: в зависимости от ситуации, но в целом, вы не ошибётесь, если будете всегда использовать кнопку.
Кнопка это элемент, предназначенный для запуска каких-либо интерактивных элементов внутри страницы. Поэтому пользователь, нажимая на кнопку, будет готов, что на странице что-то изменится. Кажется, это то, что нам нужно. Тем не менее, я считаю, что ссылки имеют некоторые преимущества в некоторых случаях.
Поэтому я задаю себе второй вопрос: должен ли изменившийся контент получить фокус?
И опять ответом на этот вопрос будет фраза в зависимости от ситуации. Но можно помочь себе, просто посмотрев на DOM-дерево и оценив, насколько далеко триггер находится от целевого контента.
Если целевой контент находится сразу после триггера, то стоит использовать кнопку и обойтись без автоматического фокуса на целевой элемент. Поскольку пользователь следующим табом попадает на появившийся контент.
<button>Trigger Text</button> <div id="target"> <p>Target content.</p></div>
Но если целевой контент находится на некотором расстоянии от активирующего его элемента, то, возможно, стоит посмотреть в сторону не очень модных, но отлично работающих гиперссылок с фрагментами.
<a href="#target">Trigger Text</a> <div id="target"> <p>Target content.</p></div>
Реальный пример
Предположим, в макете, предоставленном дизайнером, имеется элемент Войти, расположенный в шапке сайта. И, согласно дизайну, по нажатию должно открыться модальное окно с формой входа. Сам код модального окна, скорее всего, находится в конце DOM-дерева. В этом случае использование ссылки не кажется мне плохой идеей.
При работе со ссылками, в отличие от кнопок, пользователь ожидает, что после клика он будет куда-то перенаправлен. И, в целом, модальные окна можно рассматривать как отдельные страницы, поэтому результат не будет неожиданным для пользователя.
Вернёмся к вопросам, поставленным выше: Должен ли быть триггер кнопкой или ссылкой? и Должен ли фокус автоматически переключиться на целевой контент? Ответ на эти вопросы можно найти, просто ответив на вопрос: Как далеко друг от друга находятся триггер и целевой контент.
Далее я добавляю на страницу немного JavaScript, чтобы убедиться, что пользователи клавиатуры и мыши могут взаимодействовать с созданным компонентом. Конечно, не обходится без небольшой магии с
tabindex
и методом focus()
, которые
заслуживают отдельной статьи.Теперь самое время подумать о пользователях скринридеров. Первое, что стоит сделать это добавить атрибуты
aria-expanded
в триггер и
aria-hidden
в целевой контент.// Таргет не активирован
Триггер - aria-expanded="false",
Целевой контент - aria-hidden="true".
// Пользователь нажал на таргет элемент
Триггер - aria-expanded="true",
Целевой контент - aria-hidden="false".
Ещё существует атрибут
aria-controls
, который позволяет явно указать
взаимосвязь между целевым компонентом и триггером.
<button aria-controls="target">Trigger Text</button><div id="target"> <p>Target content.</p></div>
Правда, он не всегда работает так, как это можно ожидать.
В качестве заключения
Для более наглядного примера я реализовал два
codepan
:
один с триггером в виде кнопки, а второй со ссылкой (кнопка,
ссылка).
В чём разница, спросите вы? Всё просто: в примере со ссылкой
целевой контент сразу получил фокус без каких-то дополнительных
телодвижений со стороны разработчика.Это наводит меня на мысль, что, возможно, если вы работаете над SPA, то стоит задуматься, стоит ли делать SPA, а потом пытаться сделать его доступным, продумывая, куда перевести фокус в появившемся контенте. Где должен оказаться фокус после исчезновения появившегося контента, что будет с фокусом, когда целевой контент скроется? Ведь очень часто, пытаясь делать SPA доступным, вы во много повторяете функциональность, уже заложенную в браузеры.
В любом случае, я надеюсь, что эта небольшая прогулка на волне моих мыслей оказалась для вас полезной. Теперь вы знаете, как можно справиться с проблемами доступности, которые, на первый взгляд, кажутся неприступными.
И помните, что тот факт, что вы дочитали этот материал до конца, означает, что вы знаете, как решать проблемы с доступностью лучше, чем большинство разработчиков.
Спасибо за внимание, всем добра!