语义 HTML 元素的 DOM 位置提供的默认标签顺序非常方便,但有时您可能需要修改标签顺序。在 HTML 中移动元素是理想的,但可能不可行。在这些情况下,您可以使用 tabindex
HTML 属性来显式设置元素的标签位置。
tabindex
可以应用于任何元素,尽管它不一定对每个元素都有用,并且可以接受一系列整数值。使用 tabindex
,您可以为可聚焦的页面元素指定显式顺序,将原本不可聚焦的元素插入到标签顺序中,以及从标签顺序中删除元素。例如
tabindex="0"
:将元素插入到自然标签顺序中。可以通过按 Tab 键来聚焦该元素,也可以通过调用其 focus()
方法来聚焦该元素。
tabindex="-1"
:从自然标签顺序中删除元素,但仍然可以通过调用其 focus()
方法来聚焦该元素。
tabindex="5"
:任何大于 0
的 tabindex 都会将该元素带到自然标签顺序的前面。如果有多个元素的 tabindex 大于 0
,则标签顺序从大于零的最小值开始,并向上递增。
对于非输入元素(如标题、图像或文章标题)尤其如此。如果可能,最好安排您的源代码,以便 DOM 序列提供逻辑标签顺序。如果您确实使用 tabindex
,请将其限制为自定义交互控件,如按钮、标签、下拉列表和文本字段;也就是说,用户可能希望提供输入的元素。
仅将 tabindex
添加到交互式内容。即使内容很重要(例如关键图像),屏幕阅读器用户也可以在不添加焦点的情况下理解它。
在页面级别管理焦点
有时,tabindex
对于无缝的用户体验是必要的。例如,如果您构建一个具有不同内容部分的强大的单页,其中并非所有内容都同时可见。这可能意味着导航链接会更改可见内容,而无需页面刷新。
在这种情况下,识别选定的内容区域并为其赋予 tabindex
的 -1
并调用其 focus
方法。这确保内容不会出现在自然标签顺序中。这种称为管理焦点的技术使用户的感知上下文与网站的视觉内容保持同步。
在组件中管理焦点
在某些情况下,您还必须在控件级别管理焦点,例如使用自定义组件。
例如,select
元素可以接收基本焦点,但一旦聚焦,您可以使用箭头键来显示其他可选择的选项。如果您构建自定义 select
元素,则复制该行为非常重要,以便键盘用户仍然可以与您的控件进行交互。
了解要实现哪些键盘行为可能很困难。无障碍富 Internet 应用程序 (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 从一个单选按钮移动到下一个单选按钮。
模态框和键盘陷阱
最好避免手动管理焦点,因为它可能导致复杂的情况。例如,一个自动完成小部件试图管理焦点并捕获标签行为,但阻止用户离开它,直到完成为止。这称为键盘陷阱,对于用户来说可能非常令人沮丧。
WCAG 的 2.1.2 节指出,键盘焦点永远不应锁定或陷阱在一个特定的页面元素上。用户应该能够仅使用键盘在所有页面元素之间导航。
此规则的例外情况是模态框。但是,在创建模态框时,您仍应避免使用 tabindex
。使用 inert
,您可以确保用户不会意外地与元素交互(有意的键盘陷阱)。使用 <dialog>
元素(默认情况下是 inert)为用户创建模态框,同时阻止模态框外部的点击和标签。这允许用户专注于所需的选择。