语义 HTML 元素的 DOM 位置提供的默认标签页顺序非常方便,但有时您可能需要修改标签页顺序。在 HTML 中移动元素是理想的做法,但可能不可行。在这些情况下,您可以使用 tabindex
HTML 属性来明确设置元素的标签页位置。
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>
元素为用户创建模态窗口,同时屏蔽模态窗口之外的点击和标签页。这样,用户就可以专注于所需的选择。