使用 tabindex

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney

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

Browser Support

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

Source

tabindex 可以应用于任何元素,但并不一定对每个元素都有效,并且采用一系列整数值。借助 tabindex,您可以为可聚焦的页面元素指定显式顺序,将原本不可聚焦的元素插入到标签页顺序中,以及从标签页顺序中移除元素。例如:

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

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

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

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

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

在页面级别管理焦点

有时,tabindex 对提供顺畅的用户体验至关重要。例如,如果您构建了一个包含不同内容版块的强大单页,其中并非所有内容都会同时显示。这可能意味着导航链接会更改可见内容,而无需刷新网页。

在本例中,识别所选内容区域,并为其指定 tabindex-1,然后调用其 focus 方法。这样可以确保内容不会显示在自然的标签页顺序中。此技术称为管理焦点,可确保用户感知的上下文与网站的视觉内容保持同步。

管理组件中的焦点

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

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

确定要实现哪些键盘行为可能很难。Accessible Rich Internet Applications (ARIA) Authoring Practices 指南列出了组件类型及其支持的键盘操作类型。

也许您正在处理类似于一组单选按钮的自定义元素,但您对其外观和行为有自己的独特看法。

<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,并对其调用焦点方法。

<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 会尝试管理焦点并捕获标签页行为,但会阻止用户在完成之前离开该 widget。这称为“键盘陷阱”,可能会让用户感到非常沮丧。

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

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