使用 tabindex 修改 DOM 顺序

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

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

浏览器支持

  • 1
  • 12
  • 1.5
  • 不超过 4 个

来源

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

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

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

tabindex="5":任何大于 0 的 tabindex 都会将相应元素置于自然 Tab 键顺序的最前面。如果多个元素的 tabindex 均大于 0,则 Tab 键顺序会从大于零的最小值开始,并逐级向上。使用大于 0 的 tabindex 被视为反模式

对于标题、图片或文章标题等非输入元素来说尤其如此。如果可能,最好安排源代码,让 DOM 序列提供符合逻辑的 Tab 键顺序。如果您确实需要使用 tabindex,请将其限制为自定义交互式控件,例如按钮、标签页、下拉菜单和文本字段;也就是说,用户可能希望提供输入的元素。

请仅向互动式内容添加 tabindex。即使内容非常重要(例如关键图片),屏幕阅读器用户也能理解,而无需聚焦。

在页面级别管理焦点

有时,必须使用 tabindex 才能提供顺畅的用户体验。例如,如果您构建一个包含不同内容版块的强大单页,其中并非所有内容都同时可见。这意味着,导航链接会在不刷新网页的情况下更改可见内容。

在这种情况下,请标识所选内容区域,为其指定 -1tabindex 并调用其 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,并对其调用聚焦方法。

<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 从一个单选按钮到下一单选按钮的流动情况。

模态窗口和键盘陷阱

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

WCAG 第 2.1.2 节规定,键盘焦点绝不应锁定或困在某一特定页面元素上。用户应该能够只使用键盘在页面元素间来回导航。

模态规则除外。不过,在创建模态时,仍应避免使用 tabindex。借助 inert,您可以确保用户不会意外地与元素互动(故意键盘陷阱)。使用默认处于休眠状态的 <dialog> 元素为用户创建模态窗口,同时阻止在模态窗口外部点击和标签页。这样,用户就可以专注于必要的选择。