键盘导航别再全屏扫 DOM 了,`focusgroup` 让浏览器自己管 Tab 顺序

键盘导航别再全屏扫 DOM 了,`focusgroup` 让浏览器自己管 Tab 顺序

导语

你项目里是不是也有一堆自定义下拉、弹窗、侧栏、轮播,每次做无障碍键盘导航都要写一堆 keydowntabindex、焦点圈逻辑?我最近把这类交互统一收敛成一种思路:与其手动管焦点,不如让浏览器按“组件语义”自动排 Tab 顺序。focusgroup 就是这个思路里目前最值得提前落地的方案。

正文

常见场景其实很固定:侧栏打开后,焦点要进侧栏循环;弹窗出来,焦点要锁在对话框;轮播图里,左右按钮之间要能 Tab 但不跳出。

问题是这些逻辑大多散在各处:有的用 tabindex,有的用 focus(),有的在 keydown 里自己判断方向键。结果就是组件越复杂,键盘逻辑越容易漏,还经常和屏幕阅读器打架。

现在浏览器给了一个更接近语义的解法:用 focusgroup 把一组元素标记成同一组。组内的 Tab 只在组内循环,组外的默认行为不变。

好处是它把“谁和谁是一组”从 JS 逻辑里抽出来,变成 HTML 属性表达,比散落在各处的 keydown 更容易维护,也更容易被辅助技术理解。

<!-- 侧栏:Tab 只在按钮组里循环 -->
<div role="dialog" aria-modal="true" aria-label="设置">
  <div focusgroup>
    <button>个人资料</button>
    <button>通知设置</button>
    <button>隐私设置</button>
    <button>关闭</button>
  </div>
</div>

<!-- 轮播:左右按钮成组,不跳到页面其它按钮 -->
<div class="carousel" focusgroup>
  <button aria-label="上一张">←</button>
  <button aria-label="下一张">→</button>
</div>

<!-- 工具栏:一组工具键 -->
<div role="toolbar" focusgroup>
  <button>加粗</button>
  <button>斜体</button>
  <button>链接</button>
</div>

如果你用的是 React,也可以封装成更接近组件的写法。

function FocusGroup({ children, role }) {
  return (
    <div {...(role ? { role } : {})} focusgroup>
      {children}
    </div>
  );
}

// 使用
<FocusGroup role="toolbar">
  <button>加粗</button>
  <button>斜体</button>
  <button>链接</button>
</FocusGroup>

我现在的判断标准很简单:如果一个组件的键盘交互仍然靠大量 keydown 手动计算下一个元素,那它大概率该考虑收拢成 focusgroup;如果只是普通页面内容流,那就继续用默认 Tab 顺序。

这个属性真正的好处是:可访问性逻辑开始和业务逻辑分离,以后换组件库、换交互形态,焦点行为不用跟着重写。

收尾

这周你可以先挑一个最复杂的组件试:比如自定义下拉或轮播。把原来的 keydown 焦点计算替换成 focusgroup,看能不能把代码减掉一半。要是跑通了,你会发现很多以前靠 tabindexfocus() 拼出来的东西,其实本来就不该那么写。

评论区

0 条评论

登录后可评论。

查看完整榜单
查看完整榜单
查看完整榜单