使用 tabindex

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney
Alexandra Klepper
Alexandra Klepper

语义 HTML 元素的 DOM 位置提供的默认 Tab 键顺序非常方便,但有时您可能需要修改 Tab 键顺序。在 HTML 中移动元素是理想的做法,但可能不可行。在这些情况下,您可以使用 tabindex HTML 属性来明确设置元素的 Tab 位置。

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.5.
  • Safari: 3.1.

Source

tabindex 可应用于任何元素,但并非对每个元素都一定有用,并且可采用一系列整数值。借助 tabindex,您可以为可聚焦的网页元素指定明确的顺序,将原本无法聚焦的元素插入到 Tab 键顺序中,以及从 Tab 键顺序中移除元素。例如:

tabindex="0":将元素插入到自然标签页顺序中。可以通过按 Tab 键聚焦元素,也可以通过调用元素的 focus() 方法聚焦元素。

tabindex="-1":从自然标签页顺序中移除元素,但仍可通过调用元素的 focus() 方法来聚焦该元素。

tabindex="5":任何大于 0 的 tabindex 都会将相应元素置于自然 Tab 顺序的前面。如果有多个元素的 tabindex 大于 0,则标签页顺序从大于零的最低值开始,然后逐渐增大。

对于标题、图片或文章标题等非输入元素,这一点尤其重要。如果可能,最好安排源代码,使 DOM 序列提供逻辑标签页顺序。如果您确实要使用 tabindex,请将其限制为自定义互动控件,例如按钮、标签页、下拉菜单和文本字段;也就是说,用户可能会向这些元素提供输入内容。

仅向互动内容添加 tabindex。即使内容很重要(例如关键图片),屏幕阅读器用户也可以在不添加焦点的情况下理解该内容。

在页面级管理焦点

有时,tabindex 对于提供顺畅的用户体验是必要的。例如,如果您构建了一个包含不同内容部分的强大的单页应用,但并非所有内容都同时可见。这可能意味着导航链接会更改可见内容,而无需刷新网页。

在这种情况下,请确定所选内容区域并为其指定 tabindex(值为 -1),然后调用其 focus 方法。这样可确保内容不会出现在自然标签页顺序中。这种称为管理焦点的技术可让用户感知到的上下文与网站的视觉内容保持同步。

管理组件中的焦点

在某些情况下,您还必须在控件级别管理焦点,例如使用自定义组件。

例如,select 元素可以接收基本焦点,但一旦接收到焦点,您就可以使用箭头键显示其他可选择的选项。如果您构建自定义 select 元素,请务必复制该行为,以便键盘用户仍能与您的控件互动。

您可能很难确定要实现哪些键盘行为。无障碍富互联网应用 (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 创作实践指南。 第 2 部分包含设计模式列表,其中包括单选按钮组的特征表,这是与新元素最接近的现有组件。

应支持的常见键盘行为之一是向上/向下/向左/向右箭头键。为了向新组件添加此行为,我们使用了一种称为“漫游 tabindex”的技术。

漫游 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,并对其调用 focus 方法。

<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>

当用户到达最后一个(或第一个,具体取决于他们移动焦点的方向)子元素时,焦点会循环回到第一个(或最后一个)子元素。

不妨试试以下示例。在开发者工具中检查元素,观察 tabindex 从一个单选按钮移到下一个单选按钮。

模态框和键盘陷阱

最好避免手动管理焦点,因为这可能会导致复杂的情况。 例如,一个尝试管理焦点并捕获 Tab 行为的自动补全 widget,但会阻止用户离开该 widget,直到它完成为止。这称为键盘陷阱,会让用户感到非常沮丧。

WCAG 的第 2.1.2 条规定,键盘焦点绝不应锁定或困在某个特定网页元素上。用户应该能够仅使用键盘在所有网页元素之间来回导航。

此规则的例外情况是模态框。不过,您在创建模态框时仍应避免使用 tabindex。借助 inert,您可以确保用户不会意外与某个元素互动(有意设置的键盘陷阱)。使用默认情况下处于非活动状态的 <dialog> 元素为用户创建模态框,同时阻止模态框外部的点击和标签页。这样,用户就可以专注于所需的选择。