Статьи

Учимся фокусироваться ()

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

Хотя теперь можно сказать, что мой визуальный и, следовательно, когнитивный фокус изменился, сам пользовательский интерфейс не знает, на что обратило мое внимание. По крайней мере, пока я не начну физически взаимодействовать с недавно исследованным регионом. Иными словами, вращение моих глазных яблок — незаписанное событие.

В этом заключается очень распространенная, но часто не решаемая проблема доступности: если я не использую свои глаза (и руку мыши, чтобы указывать), как мне «сосредоточиться» на чем-то, чтобы потом взаимодействовать с ним? Ответ, как я уверен, вы знаете, через программную направленность . Однако это не так просто, как просто включить «фокусируемые» элементы в наши проекты. Иногда не пользователь, а интерфейс от имени пользователя должен перемещать фокус между различными областями. Это требует целенаправленного управления со стороны разработчика.

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

ScrollTop Animation

В этом примере я предлагаю вам представить, что вы «улучшили» навигационную ссылку на той же странице, чтобы вместо резкого #section1 к целевому фрагменту ссылки ( #section1 , #section1 ) вас осторожно #section1 к этому месту назначения с помощью JavaScript анимация scrollTop . Важное замечание, касающееся доступности при использовании этого метода, — это необходимость переопределить функцию по умолчанию элемента <a> .

 event.preventDefault(); 

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

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

Средство

Нам нужно сфокусировать целевой фрагмент с помощью JavaScript. Сначала нам нужно сделать фрагмент программно фокусируемым для начала, что требует использования атрибута tabindex . Значение tabindex -1 — это специальное значение, которое означает, что сценарии могут фокусировать элемент, но не пользователей. В этом случае это предпочтительнее tabindex: 0 , потому что нет никаких причин, по которым этот неинтерактивный элемент должен фокусироваться с помощью клавиши TAB .

Примечание: Спасибо Патрику и другим в комментариях за то, что они указали на то, что для значения tabindex следует использовать «-1» вместо «0», которое мы сейчас исправили.

 <section id="section1" tabindex="-1"> ... </section> 

Наша вторая задача — включить метод JavaScript focus() в обратный вызов анимации, обеспечив фокусировку фрагмента после завершения анимации.

 document.getElementById('section1').focus(); 

Наконец, это хорошая идея, чтобы записать расположение нашей подстраницы в URL, как это было бы, просто связавшись с фрагментом (например, http://my-site/#section1 ). Таким образом, мы можем скопировать адрес в виде ссылки на конкретный раздел (то есть мы можем «глубокую ссылку»). Добавьте следующую строку после выполнения focus() :

 window.location.hash = 'section1'; 

Конечно, вы должны заменить ‘section1’ на переменную, основанную на значении href соответствующей ссылки, за исключением # .

 <a href="#whatever">scroll to section 'whatever'</a> 

Результат

Небольшая демонстрация CodePen встроена ниже. Попробуйте использовать его только с TAB и SHIFT + TAB, как это делает обычный пользователь клавиатуры.

Обратите внимание, что мы добавляем атрибут tabindex на лету в нашем JavaScript. Теперь, когда мы фокусируем разделы (фрагменты), на которые мы прокручиваем, наше воспринимаемое местоположение — больше, чем просто визуальное. То есть, если я нажму клавишу TAB после перехода в новый раздел, я сфокусирую следующий фокусируемый элемент в этом разделе; гиперссылка «heydonworks.com» в следующем примере.

 <section id="section1" tabindex="-1"> <p>Donec a congue leo? Fusce ac sodales magna. Aliquam nisl enim… tristique tempus placerat at, <a href="http://heydonworks.com">heydonworks.com</a> posuere in lectus. Curabitur consectetur faucibus nisl ac varius.</p> </section> 

Если бы мы не фокусировали section1 , нажатие клавиши TAB сфокусировало бы следующий элемент после стимулирующей ссылки, которая вернула бы окно просмотра обратно в наш блок навигации. Другими словами, пользователи клавиатуры вернутся на круги своя.

 <a href="#section1">Section 1</a> <a href="#section2">Section 2</a> <!-- not where we want to be --> 

Закрытие диалогов (модальные окна)

Вот еще один маленький пример. Давайте представим, что пользователь нажал <button> и он открыл диалоговое окно или модальное окно. Ради аргумента этот диалог просит пользователя подтвердить или отменить предполагаемое действие, инициированное кнопкой.

Чтобы сделать открытие этой кнопки доступным, мы должны focus() диалог во многом так же, как мы сфокусировали фрагмент страницы в последнем примере. Используя jQueryUI, первая из кнопок диалога (в нашем случае «подтвердить») будет сфокусирована. Другие реализации фокусируют контейнер диалога. В любом случае, пользователи программно отправляются в нужное место .

 $('dialog button:first-of-type').focus(); 

Вопрос в том, что происходит, когда фокус закрывается? Если мы ничего не сделаем, новый скрытый диалог обязательно потеряет фокус, но ничто не займет его место. Во многих пользовательских агентах это означало бы, что <body> фокусируется по умолчанию, заставляя пользователей просматривать документ, чтобы снова найти свое место.

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

 $(this).attr('data-dialog-trigger', true); 

В конце метода close() диалога мы бы просто сфокусировали оригинальный элемент:

 $('[data-dialog-trigger]').focus(); 

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

Вывод

Распространенной ошибкой является отождествление прогрессивного улучшения с доступностью; думать, что проверка того, что что-то ухудшает работу с отключенным JavaScript (как в этом случае), означает, что это «доступно». Конечно, это делает его доступным для тех, у кого нет JavaScript, но большинство пользователей программ для чтения с клавиатуры и экрана взаимодействуют с вашими приложениями с помощью JavaScript, как и все остальные. Хитрость заключается в том, чтобы использовать JavaScript таким образом, чтобы он учитывал различное поведение и вклад всех ваших пользователей и любые вспомогательные технологии, которые они могли бы использовать.

Еще одна вещь: если вам когда-либо поручено работать над одностраничным приложением, созданным, скажем, с Ember.js или AngularJS, используйте базу кода JavaScript для метода focus() . Такие приложения полностью переписывают навигацию с использованием «представлений»; динамические перестройки единственной страницы. Без некоторого тщательного управления фокусировкой перестройка DOM таким способом может довольно быстро испортить доступность. Если ваш grep находит менее пары экземпляров .focus , может потребоваться много работы.