跳转后焦点需真正落在目标区
别名: 锚点焦点 · skip target · 跳转后焦点
概念解释
激活跳过链接之后,键盘焦点必须落到主内容这个目标节点上,下一次 Tab 从那里开始。只把视口滚过去、焦点仍停在跳过链接上,不算跳转成功:再按 Tab,人会回到导航的下一环,税没免掉,只是屏幕晃了一下。
目标区要能接收焦点。一个不能聚焦的 <main> 常常让用户代理把焦点留在原链接,或丢到 body。滚动位置和焦点位置是两件事。
机制
href="#main" 默认做的是视口滚动。历史上,无 tabindex 的非交互元素不会成为焦点目标,所以激活后焦点仍在跳过链接。下一次 Tab 按的是「跳过链接的下一个」,也就是顶栏里的第一项——捷径被短路了。给目标加上 tabindex="-1"(可被脚本和锚点聚焦,但不插入 Tab 序列)是补上这截契约的常用办法;有的用户代理近年已能把锚点焦点移到目标,但不能假定所有组合都如此。
另一类失败:id 指错节点,滚到了侧栏或一个空的包装 div;或者主内容在跳转后才异步渲染,锚点当时还不存在,焦点无处可去。单页应用路由之后若销毁并重建 <main>,旧 id 的跳转会打到空。
怎么研究
激活跳过链接,立刻查 document.activeElement,再按一次 Tab,看落点是主内容里的第一个控件,还是导航里的某个链接。三件都记:滚动是否发生、焦点节点是谁、下一次 Tab 去哪。只看滚动会得到假阳性。
覆盖:刚加载、客户端路由一次之后、主内容延迟出现的骨架屏。这三种时刻的锚点存活状态不同。
边界
目标聚焦时不必画出和按钮一样的厚焦点环——<main> 被程序化聚焦,环可能干扰阅读。可以让容器的焦点样式更克制,但焦点必须在这个节点上。多个跳过入口(跳过导航、跳过搜索)每个都要落到自己的目标,不能都滚到页面顶端。打印预览、嵌入的阅读视图如果没有 <main>,要指定等价的内容容器,不要把跳转指向已经不在视图里的外壳。
怎么落地
- 主内容容器设置稳定的
id,并使其可被程序化聚焦(常用tabindex="-1")。 - 跳过链接的
href指向该 id;跳转后确认activeElement是该容器或其内部第一个有意义的控件。 - 异步渲染主内容时,等目标存在再完成跳转,或把焦点移到随后出现的容器上。
- 验证:激活跳过,再 Tab 一次。若焦点回到顶栏,只是滚了屏,目标没有接住焦点。