你做了一个数据表格,行很长,列很多,容器加了横向滚动。鼠标测试没问题,就上线了。

但键盘用户按Tab键进入表格后,焦点落在某个单元格上。他们按方向键想横向阅读,没反应。再按Tab,焦点直接跳到表格外的下一个交互元素。内容明明存在,屏幕阅读器用户也能正常访问,可键盘用户就是没法滚动——除非用鼠标

打开网易新闻 查看精彩图片

你可能从没发现这个问题,因为测试时只用鼠标。屏幕阅读器用户也没抱怨,因为他们走的是无障碍树,不是滚动容器。唯一被困住的,是那些视力正常却依赖键盘的用户——而大多数团队根本不测这个场景。

我也是。直到有人提了一个我复现不了的bug,直到我放下鼠标。

焦点管理和滚动容器是两套系统

键盘焦点跟着Tab顺序走。Tab顺序又跟着交互元素走——按钮、链接、输入框,凡是浏览器认定"可操作"的东西。这是键盘导航的规范设计。

滚动容器完全是另一套机制。它是布局原语。当你给元素设置overflow为auto、scroll或hidden时,浏览器会以不同方式处理溢出内容。浏览器的职责是管理溢出,而非导航溢出。规范从未将overflow归类为交互属性。

两套系统之间的缝隙,就是键盘用户掉进去的地方。

这不是浏览器bug。所有主流浏览器表现一致,因为它们遵循同一套规范。滚动容器和焦点管理各自都在正常工作——只是设计之初就没打算配合。

这些CSS属性会悄无声息地制造滚动容器

刚才提到的几个overflow值会影响溢出处理,但哪些值真正创建滚动容器?auto最明显,但滚动容器总在你意想不到的地方冒出来。

记住:overflow是简写属性,它的构成方式有点反直觉。比如,把overflow-x设为auto来处理横向溢出,会隐式地把overflow-y也设为auto。于是,你本意只做横向滚动的容器,同时变成了纵向滚动容器——而键盘用户两个方向都没法滚。

代码层面,这样写:

.table-wrapper { overflow-x: auto; }

等价于:

.table-wrapper { overflow-x: auto; overflow-y: auto; }

同样的问题也出在overflow: hidden上。多数开发者用它裁剪内容或清除浮动,但hidden同样会创建滚动容器。内容只是被裁剪,并非消失——这可能是一种意外的"数据丢失"。