Использование табиндекса

Изменение порядка DOM с помощью tabindex

Дэйв Гэш
Dave Gash
Меггин Кирни
Meggin Kearney

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

Поддержка браузера

  • 1
  • 12
  • 1,5
  • ≤4

Источник

tabindex может применяться к любому элементу (хотя он не обязательно полезен для каждого элемента) и принимает диапазон целочисленных значений. Используя tabindex , вы можете указать явный порядок для фокусируемых элементов страницы, вставить в порядок табуляции элемент, который в противном случае не мог бы быть фокусируемым, и удалить элементы из порядка табуляции. Например:

tabindex="0" : вставляет элемент в естественный порядок табуляции. Элемент можно сфокусировать, нажав клавишу Tab , а элемент можно сфокусировать, вызвав его метод focus()

<custom-button tabindex="0">Press Tab to Focus Me!</custom-button>

Нажмите Tab, чтобы сфокусировать меня!

tabindex="-1" : удаляет элемент из естественного порядка табуляции, но элемент все равно можно сфокусировать, вызвав его метод focus()

// TODO: DevSite - Code sample removed as it used inline event handlers

// TODO: DevSite – удален пример кода, поскольку в нем использовались встроенные обработчики событий

tabindex="5" : ​​любой tabindex больше 0 перемещает элемент в начало естественного порядка табуляции. Если существует несколько элементов с индексом табуляции больше 0, порядок табуляции начинается с наименьшего значения, большего нуля, и идет вверх. Использование tabindex больше 0 считается антишаблоном .

<button>I should be first</button>
<button>And I should be second</button>
<button tabindex="5">But I jumped to the front!</button>

Это особенно верно в отношении невводных элементов, таких как заголовки, изображения или заголовки статей. Добавление tabindex к элементам такого типа является контрпродуктивным. Если возможно, лучше всего расположить исходный код так, чтобы последовательность DOM обеспечивала логический порядок табуляции. Если вы используете tabindex , ограничьте его пользовательскими интерактивными элементами управления, такими как кнопки, вкладки, раскрывающиеся списки и текстовые поля; то есть элементы, для которых пользователь может ожидать ввода данных.

Не беспокойтесь о том, что пользователи программ чтения с экрана пропустят важный контент из-за отсутствия tabindex . Даже если контент очень важен, например изображение, если пользователь не может с ним взаимодействовать, нет смысла делать его фокусируемым. Пользователи программ чтения с экрана по-прежнему смогут понять содержимое изображения, если вы обеспечите правильную поддержку атрибута alt , о чем мы вскоре расскажем.

Управление фокусом на уровне страницы

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

В этом случае вам, вероятно, придется идентифицировать выбранную область содержимого, присвоить ей tabindex табуляции -1, чтобы она не отображалась в естественном порядке табуляции, и вызвать ее метод focus . Этот метод, называемый управлением фокусом , синхронизирует воспринимаемый пользователем контекст с визуальным контентом сайта.

Управление фокусом в компонентах

Управление фокусом при изменении чего-либо на странице важно, но иногда вам нужно управлять фокусом на уровне элемента управления — например, если вы создаете собственный компонент.

Рассмотрим собственный элемент select . Он может получить базовый фокус, но, оказавшись там, вы можете использовать клавиши со стрелками, чтобы открыть дополнительные функции (выбираемые параметры). Если бы вы создавали собственный элемент select , вам бы хотелось предоставить такое же поведение, чтобы пользователи, которые в основном полагаются на клавиатуру, могли взаимодействовать с вашим элементом управления.

<!-- Focus the element using Tab and use the up/down arrow keys to navigate -->
<select>
    <option>Aisle seat</option>
    <option>Window seat</option>
    <option>No preference</option>
</select>

Понять, какое поведение клавиатуры следует реализовать, может быть сложно, но есть полезный документ, к которому вы можете обратиться. В руководстве «Практика разработки доступных полнофункциональных интернет-приложений (ARIA)» перечислены типы компонентов и типы действий с клавиатуры, которые они поддерживают. Мы рассмотрим ARIA более подробно позже, а сейчас давайте воспользуемся руководством, которое поможет нам добавить поддержку клавиатуры в новый компонент.

Возможно, вы работаете над новыми пользовательскими элементами , напоминающими набор переключателей, но с вашим уникальным внешним видом и поведением.

<radio-group>
    <radio-button>Water</radio-button>
    <radio-button>Coffee</radio-button>
    <radio-button>Tea</radio-button>
    <radio-button>Cola</radio-button>
    <radio-button>Ginger Ale</radio-button>
</radio-group>

Чтобы определить, какая поддержка клавиатуры им нужна, вы можете просмотреть руководство ARIA Authoring Practices . Раздел 2 содержит список шаблонов проектирования, и в этом списке находится таблица характеристик радиогрупп — существующего компонента, который наиболее точно соответствует вашему новому элементу.

Как видно из таблицы, одним из распространенных вариантов поведения клавиатуры, которое должно поддерживаться, являются клавиши со стрелками вверх/вниз/влево/вправо. Чтобы добавить такое поведение к новому компоненту, мы воспользуемся методом перемещения tabindex .

Выдержка из спецификации W3C для переключателей.

Перемещающийся tabindex работает, устанавливая tabindex в -1 для всех дочерних элементов, кроме активного в данный момент.

<radio-group>
    <radio-button tabindex="0">Water</radio-button>
    <radio-button tabindex="-1">Coffee</radio-button>
    <radio-button tabindex="-1">Tea</radio-button>
    <radio-button tabindex="-1">Cola</radio-button>
    <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

Затем компонент использует прослушиватель событий клавиатуры, чтобы определить, какую клавишу нажимает пользователь; когда это происходит, он устанавливает табиндекс ранее сфокусированного дочернего tabindex на -1, устанавливает табиндекс дочернего tabindex который должен быть сфокусирован, на 0 и вызывает для него метод фокуса.

<radio-group>
    // Assuming the user pressed the down arrow, we'll focus the next available child
    <radio-button tabindex="-1">Water</radio-button>
    <radio-button tabindex="0">Coffee</radio-button> // call .focus() on this element
    <radio-button tabindex="-1">Tea</radio-button>
    <radio-button tabindex="-1">Cola</radio-button>
    <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

Когда пользователь достигает последнего (или первого, в зависимости от направления перемещения фокуса) дочернего элемента, вы снова выполните цикл и фокусируете первого (или последнего) дочернего элемента.

Вы можете попробовать готовый пример ниже. Проверьте элемент в DevTools, чтобы увидеть, как tabindex перемещается от одного радио к другому.

Вода Кофе Чай Кола Имбирный эль

// TODO: DevSite – удален пример кода, поскольку в нем использовались встроенные обработчики событий

Вы можете просмотреть полный исходный код этого элемента на GitHub.

Модалы и ловушки клавиатуры

Иногда, когда вы управляете концентрацией внимания, вы можете попасть в ситуацию, из которой не сможете выбраться. Рассмотрим виджет автозаполнения, который пытается управлять фокусом и фиксирует поведение вкладки, но не позволяет пользователю покинуть ее, пока она не будет завершена. Это называется ловушкой клавиатуры , и это может очень расстраивать пользователя. Раздел 2.1.2 контрольного списка Web AIM решает эту проблему, утверждая, что фокус клавиатуры никогда не должен блокироваться или захватываться одним конкретным элементом страницы . Пользователь должен иметь возможность переходить ко всем элементам страницы и обратно, используя только клавиатуру.

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

Модальное окно, предлагающее пользователю сохранить свою работу.

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

Есть несколько предложений о том, как упростить эту задачу для разработчиков, включая элемент <dialog> , но они пока не имеют широкой поддержки браузеров.

См. эту статью MDN для получения дополнительной информации о <dialog> и этот модальный пример для получения дополнительной информации о модальных окнах.

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

  1. Используя document.querySelector , выберите модальные и наложенные элементы div и сохраните их ссылки.
  2. При открытии модального окна сохраните ссылку на элемент, который был в фокусе при открытии модального окна, чтобы вы могли вернуть фокус на этот элемент.
  3. Используйте прослушиватель нажатия клавиш , чтобы захватывать клавиши по мере их нажатия, когда модальное окно открыто. Вы также можете прослушать щелчок по фоновому наложению и закрыть модальное окно, если пользователь нажмет на него.
  4. Затем получите коллекцию фокусируемых элементов в модальном окне. Первый и последний фокусируемые элементы будут действовать как «часовые», сообщая вам, когда нужно зациклить фокус вперед или назад, чтобы оставаться внутри модального окна.
  5. Отобразите модальное окно и сфокусируйте первый фокусируемый элемент.
  6. Когда пользователь нажимает Tab или Shift+Tab , перемещайте фокус вперед или назад, циклически переходя к последнему или первому элементу в зависимости от ситуации.
  7. Если пользователь нажимает Esc , закройте модальное окно. Это очень полезно, поскольку позволяет пользователю закрывать модальное окно без поиска конкретной кнопки закрытия, и это приносит пользу даже пользователям, использующим мышь.
  8. Когда модальное окно закрыто, скройте его и фоновое наложение и восстановите фокус на ранее сохраненном ранее элементе.

Эта процедура дает вам удобное и удобное модальное окно, которое каждый может эффективно использовать.

Для получения более подробной информации вы можете изучить этот пример кода и просмотреть живой пример на завершенной странице .