J3.02.5dynamic focus order设计研究

焦点顺序应随可见的动态变化(如展开、隐藏)实时更新

别名: 展开后的 Tab 序列 · 隐藏项仍可聚焦 · accordion focus

概念解释

可 Tab 的集合不是页面加载时拍好的一张名单,而是当前可见对象的活集合。手风琴展开,里面的链接和字段必须立刻进入序列;再收起,它们必须立刻离开。选项卡切走、折叠面板关上、移动端菜单收起,同一条规则。顺序不随可见性改写,人就会 Tab 进一块看不见的区域,或永远走不到刚展开的内容。

这和「新节点插入后焦点停在原按钮」不是同一件事。那是焦点停在哪;这是名单里还有谁。

机制

从键盘的角度看,节点有三种不同的「不在」:display: none / hidden 通常会把它移出序列;visibility: hidden 或透明度为 0 的层,视觉没了,焦点往往还在;aria-hidden 只改辅助技术树,不自动改 Tab。离屏菜单用负坐标藏在视口外,对指针等于没有,对 Tab 仍是一长串真实控件。

展开失败的镜像是:内容已经画出来,却还带着 tabindex="-1" 或父级 inert 没摘掉,视觉上的新字段键盘进不去。产品把「可见」做成了样式开关,把「可到达」留在了上一次的状态。两套开关不同步,活集合就冻在过期名单上。

怎么研究

对每一类披露控件做两次遍历:收起态 Tab 一周,记下落点;展开后再 Tab 一周,比较集合差。应收起却仍能聚焦的,记「幽灵停靠」;应展开却进不去的,记「名单未写入」。

移动端汉堡菜单特别容易冻名单:关上之后图标消失,序列里还留着那些链接,焦点会跑到视口外。把这个状态单独测。

边界

预渲染但尚未进入当前步骤的向导页,应当不可聚焦,即使 DOM 里已经有字段。轮播里不在当前帧的幻灯,同样不应停靠。相反,对屏幕外但仍「逻辑可见」的内容(例如可滚动容器里尚未滚到的条目)应保持在序列中——那不是隐藏,是溢出。inertaria-hidden 叠在动画过程中会有几帧不同步,动画结束时集合必须已经改完,不能把修正推迟到下一次点击。

怎么落地

  • 隐藏即移出序列:用 hiddendisplay: noneinert,不要只靠透明度或挪到屏外。
  • 展开完成的同一时刻摘掉 inert / 负 tabindex,让新字段可到达。
  • 验证:打开再关上导航抽屉或手风琴,只按 Tab。关上后焦点若走进空白,或打开后新链接要绕很远才到,活集合没有跟着改。

延伸

  • 同组J3.02.1 焦点顺序需与视觉顺序一致 · J3.02.2 浮层需捕获焦点并可退出 · J3.02.3 无法退出的焦点陷阱是阻断性缺陷 · J3.02.4 动态插入的元素若不显式管理焦点,会默认停留在原处造成脱节 · J3.02.6 检测焦点顺序问题需要实际用键盘遍历而非仅检查代码顺序 · J3.02.7 多层嵌套的浮层各自捕获焦点时可能相互冲突形成死锁
  • 相邻J5.10 名称、角色与状态 · J2.14 语义结构与标题层级 · E4.11 非模态面板
  • 站内检索inert · hidden tab stop · disclosure focus

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/J3.02.5