使用 tabindex

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney

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

浏览器支持

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

来源

tabindex 可应用于任何元素,但不一定在每个元素上都有用,并且接受某一范围的整型值。借助 tabindex,您可以为可聚焦的页面元素指定显式顺序、在 Tab 键顺序中插入原本不可聚焦的元素,以及从 Tab 键顺序中移除元素。例如:

tabindex="0":在自然 Tab 键顺序中插入一个元素。可通过按 Tab 键聚焦该元素,也可通过调用其 focus() 方法聚焦该元素。

tabindex="-1":从自然 Tab 键顺序中移除某个元素,但仍可通过调用其 focus() 方法聚焦该元素。

tabindex="5":只要 tabindex 大于 0,就会将该元素移至自然 Tab 键顺序的最前面。如果有多个元素的 tabindex 均大于 0,Tab 键顺序将以大于 0 的最小值为起点,从小到大排序。

这在标题、图片或文章标题之类的非输入元素上体现得尤为明显。如有可能,最好适当安排源代码,让 DOM 序列具有符合逻辑的 Tab 键顺序。如果您一定要使用 tabindex,请将其使用范围限定在按钮、标签页、下拉菜单和文本字段之类的自定义交互式控件;也就是说,用户可能需要提供输入的元素。

请仅向互动内容添加 tabindex。即使内容很重要(例如关键图片),屏幕阅读器用户也无需添加焦点即可理解它。

管理页面一级的焦点

有时,为了提供流畅的用户体验,tabindex 是必不可少的。例如,如果您构建一个强健的单一页面,其中包含不同的内容区域,这些区域并非全都同时可见。这可能意味着导航链接会更改可见内容,而无需刷新页面。

在这种情况下,请找到选定的内容区域,将其 tabindex 指定为 -1,并调用其 focus 方法。这样可以确保内容不会出现在自然 Tab 键顺序中。这种称作管理焦点的方法可让用户的感知上下文与网站的视觉内容保持同步。

管理组件中的焦点

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

例如,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>

当用户到达最后一个(或第一个,取决于其移动焦点的方向)子项时,焦点会循环返回到第一个(或最后一个)子项。

请尝试以下示例。在 DevTools 中检查该元素,观察 tabindex 从一个单选按钮到下一单选按钮的流动情况。

模态窗口和键盘陷阱

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

WCAG 2.1.2 节规定,键盘焦点不得锁定或卡在某个特定网页元素上。用户应该能够仅使用键盘来浏览所有网页元素。

此规则的例外是模态窗口。不过,您在创建模态窗口时仍应避免使用 tabindex。借助 inert,您可以确保用户无法意外与元素互动(有意为之的键盘陷阱)。使用默认处于不活跃状态的 <dialog> 元素为用户创建模态窗口,同时屏蔽模态窗口之外的点击和标签页。这样,用户就可以专注于所需的选择。