Управление фокусом при помощи tabindex
Стандартные HTML-элементы, такие как <button>
или <input>
, доступны с клавиатуры по умолчанию. Если вы создаете собственные интерактивные компоненты, используйте атрибут tabindex
, чтобы они также были доступны с клавиатуры.
Проверьте, доступны ли элементы управления с клавиатуры #
Некоторые проблемы с доступностью легко выявляются при помощи таких инструментов, как Lighthouse, однако существуют моменты, которые может проверить только человек.
Попробуйте использовать клавишу Tab
для навигации по вашему сайту. Все ли интерактивные элементы управления удается выбрать? Если ответ отрицательный, возможно, необходимо сделать их фокусируемыми при помощи атрибута tabindex
.
Включение элемента в последовательность перехода #
Чтобы включить элемент в естественную последовательность перехода по Tab, используйте tabindex="0"
. Например:
<div tabindex="0">Focus me with the TAB key</div>
Установить фокус на элементе можно при помощи клавиши Tab
или метода focus()
.
Исключение элемента из последовательности перехода #
Исключить элемент можно при помощи tabindex="-1"
. Например:
<button tabindex="-1">Can't reach me with the TAB key!</button>
Это позволяет исключить элемент из естественной последовательности перехода по Tab, однако на элементе по-прежнему можно будет установить фокус при помощи метода focus()
.
Обратите внимание, что атрибут tabindex="-1"
не распространяется на потомки элемента: они продолжат быть частью последовательности перехода вне зависимости от того, находились ли они там изначально или были включены при помощи tabindex
. Чтобы исключить элемент из последовательности перехода вместе со всеми его потомками, можно воспользоваться polyfill-библиотекой inert
из репозитория WICG. Она имитирует поведение предлагаемого атрибута inert
, который запрещает выбор элементов или их чтение при помощи вспомогательных технологий.
Избегайте tabindex > 0
#
Значения tabindex
больше 0 позволяют переместить элемент в начало естественного порядка перехода. Если на странице несколько элементов с tabindex
больше 0, то самый высокий приоритет имеют элементы с наименьшим значением.
Использование tabindex
со значениями больше 0 считается анти-паттерном, поскольку программы чтения с экрана при перемещении по странице руководствуются порядком DOM, а не порядком перехода по Tab. Для того чтобы изменить порядок следования элементов при переходе по Tab, следует изменить их порядок в DOM.
Lighthouse позволяет с легкостью обнаруживать элементы с tabindex
> 0. Запустите проверку доступности (Lighthouse > Options > Accessibility) и изучите результаты проверки «No element has a [tabindex] value greater than 0».
Создавайте доступные компоненты, используя прием «блуждающий tabindex
» #
Если вы разрабатываете сложный компонент, вам может потребоваться дополнительная поддержка клавиатуры помимо фокусировки. Например, рассмотрим встроенный элемент select
. Он поддерживает фокусировку, однако при помощи клавиш со стрелками можно получить доступ к дополнительным функциям (выбору вариантов).
Чтобы реализовать аналогичную функциональность в нестандартных компонентах, используйте метод под названием «блуждающий tabindex
». Суть метода заключается в том, что для всех дочерних элементов, кроме активного в данный момент, устанавливается tabindex
-1. Затем компонент использует слежение за событиями клавиатуры для определения нажатия клавиш.
Когда пользователь нажимает клавишу, компонент присваивает ранее сфокусированному дочернему элементу tabindex
-1, а элементу, который должен получить фокус, — tabindex
0, после чего вызывает для него метод focus()
.
Было
<div role="toolbar">
<button tabindex="-1">Undo</div>
<button tabindex="0">Redo</div>
<button tabindex="-1">Cut</div>
</div>
Стало
<div role="toolbar">
<button tabindex="-1">Undo</div>
<button tabindex="-1">Redo</div>
<button tabindex="0">Cut</div>
</div>
This HTML renders a modal dialog:
<div role="dialog" aria-labelledby="dialog-header">
<button aria-label="Close"></button>
<h2 id="dialog-header">
Do you want to allow notifications from this website?
</h2>
<button>No</button>
<button>Yes</button>
</div>
What is the tab order for the elements in the sample?
- The Close button
- The No button
- The Yes button
Only the <button>
elements are included in the tab order because they're the only standardized HTML form elements. To insert other elements into the tab order, you would add a tabindex
attribute.
<section tabindex="-1">
<h2>Cat facts</h2>
<ul>
<li>A group of cats is called a <a href="https://m-w.com/dictionary/clowder">clowder</a>.</li>
<li>Most cats are <a href="https://www.catfacts.org/catnip.html"> unaffected by catnip</a>.</li>
</ul>
</section>
Which elements from the sample are included in the tab order?
Only the <a>
elements are included in the tab order.
The <section>
element is not in the tab order because it has a negative tabindex
value. (It can, however, be focused using the focus()
method.) The tabindex
value for the <section>
element doesn't affect its children.
This HTML renders a popup menu followed by a search input:
<div role="menu" tabindex="0">
<a role="menuitem" href="/learn/" tabindex="-1">Learn</a>
<a role="menuitem" href="/measure/" tabindex="-1">Measure</a>
<a role="menuitem" href="/blog/" tabindex="-1">Blog</a>
<a role="menuitem" href="/about/" tabindex="-1">About</a>
</div>
<input tabindex="1" type="text" role="search" aria-label="Search" placeholder="Search">
Which element in the sample comes first in the tab order?
The Search text input comes first in the tab order. Because it has a tabindex
greater than zero, it jumps to the front of the tab order.
(This behavior is likely to cause confusion if the menu is positioned on the page before the search input. This is an example of why having a tabindex
value greater than zero is considered an anti-pattern.)
This HTML renders a custom radio group, which should have a roving tabindex
. (To keep things simpler, ignore the aria-*
attributes for now.)
<div role="radiogroup" aria-labelledby="breed-header">
<h3 id="breed-header">Your cat's breed</h3>
<div role="radio" aria-checked="false" tabindex="0">Persian</div>
<div role="radio" aria-checked="false" tabindex="-1">Bengal</div>
<div role="radio" aria-checked="false" tabindex="-1">Maine Coon</div>
</div>
When a role="radio"
element is focused, what should happen when a user presses the Right
arrow key?
- Change the
tabindex
values for all radio elements in the group to -1. - If there's a radio element after the one that's focused, set its
tabindex
value to 0. - If there's no radio element after the one that's focused, set the
tabindex
value of the first radio element in the group to 0. - Focus the radio element that now has a
tabindex
of 0.
That's a lot—and it doesn't even include ARIA attributes! This is an example of why it's easier to use built-in elements with built-in keyboard behavior whenever you can.
Советы по реализации поддержки клавиатуры #
Если вы не уверены насчет того, какой уровень поддержки клавиатуры может потребоваться для ваших нестандартных компонентов, обратитесь к руководству ARIA Authoring Practices 1.1. В нем приводятся распространенные паттерны пользовательских интерфейсов и рассказывается о том, какие клавиши должны поддерживаться в ваших компонентах.