焦点不得被固定元素遮挡
别名: 粘滞栏挡焦点 · sticky header · scroll-padding
概念解释
焦点可以环很亮、替代也写了,仍然看不见——被粘滞顶栏、底栏、Cookie 条、客服气泡挡住。浏览器把聚焦控件滚进视口时,算的是文档视口,不算 position: sticky / fixed 占用的那一层。结果是:键盘已经停在某个输入上,屏幕上那一块却是导航或广告。焦点不得被固定层遮挡指的是控件连同它的指示必须出现在未被铬条盖住的可视矩形里。
机制
滚动对齐默认把目标送到视口边缘。粘滞栏钉在那条边上,目标的上半或下半(常常是整块)进到栏的 z-index 下面。环画在控件盒子上,栏是另一层,对比再高也救不了被盖住的像素。scroll-margin / scroll-padding 把「视口」改成「减去铬条之后的安全区」,让滚动对准时预留栏高。
第二层是动态铬条:滚动才出现的顶栏、展开的底栏购物车、迟到的 Cookie 横幅,会在焦点已经落下之后再盖上来。放大后栏相对视口更大,遮挡更容易发生,但根因仍是固定层与滚动对齐,而不是字号本身。这和焦点顺序错乱、焦困不同:Tab 顺序可以完全正确,停驻点就是在栏底下。
怎么研究
打开粘滞头和底栏,只用键盘走完长表单和长文内链。每一停检查控件矩形与固定层矩形是否相交。改 scroll-padding-top/bottom 前后对比被挡次数。
自变量:固定层高度、是否设置 scroll-padding / scroll-margin、横幅是否后出现。 因变量:被遮挡的焦点次数、部分遮挡还是完全遮挡、用户能否看见指示。
Cookie 条与聊天组件要在到达后重新走一遍,不要只测初始 DOM。
边界
用户自己拖动的放大镜盖住焦点,是视口工具几何,不是页面铬条。关闭后焦点仍留在屏幕外菜单里,是焦点管理失败。短暂 Toast 盖住一两秒,若用户无法与被盖控件交互,仍算遮挡;纯状态气泡且不抢交互可另论。模态里的焦点被模态自己的层接住,不算被页面粘滞栏挡——但模态上再叠一条站点底栏,仍会挡。
怎么落地
- 按粘滞头、底栏的实际高度给根元素设
scroll-padding(或给目标设scroll-margin),让聚焦滚动停在安全区。 - 后出现的横幅要么加入 Tab 顺序并可关掉,要么出现时不要盖住当前焦点;挡住了就把焦点可见区域让出来。
- 不要在焦点控件上再盖一层不可关的聊天钮或广告条。
- 验证:键盘走完带粘滞头和底栏的长页。每一停,控件连指示完整露在两栏之间。临时加高顶栏,若立刻出现遮挡,说明 padding 没有跟上高度。