题目与场景
页面使用 overflow: auto,操作前没有溢出,操作后出现经典滚动条。滚动条占用视口内联方向的空间,居中内容因此改变位置。请说明 CSS 方案、适用边界、回退和量化验证。
面试官考察什么
- 是否理解
scrollbar-gutter作用于滚动盒,且属性不会继承。 - 能否区分经典滚动条与覆盖式滚动条,并解释
stable与both-edges。 - 是否知道根元素、
body和嵌套滚动容器的作用域差异。 - 能否把弹窗滚动锁定、RTL、旧浏览器和 CLS 监测放进完整方案。
先问哪些澄清问题
确认跳动发生在视口还是内部滚动容器,操作系统是否使用覆盖式滚动条,页面是否需要 RTL,弹窗是否通过锁定页面滚动实现,以及目标浏览器和无障碍要求。还要确认布局必须保持对称,还是只需避免内容在滚动条出现时向一侧移动。
30 秒回答框架
我会先在实际滚动盒上使用 scrollbar-gutter: stable,让经典滚动条出现前后预留同一侧空间;需要对称居中时使用 stable both-edges。视口场景配置根元素,内部列表单独配置自己的滚动盒。覆盖式滚动条通常不占空间,所以不会凭空产生可预留的宽度。弹窗锁滚动、RTL 和旧浏览器都保留回退路径,最后用布局位移观测和真实设备矩阵验证。
深入拆解
- 确定滚动盒。 根元素控制视口;
body的声明不会自动替代根元素。内部面板若独立滚动,必须在该面板设置属性。 - 选择值。
stable为经典滚动条预留内联方向空间;both-edges再在另一侧增加等宽空间,适合需要保持几何居中的布局。 - 理解覆盖式滚动条。 覆盖式滚动条叠在内容上,通常不消耗布局空间;用户代理和操作系统决定滚动条模式,CSS 不能强制把它变成经典模式。
- 处理弹窗。 让弹窗打开时的滚动锁定与关闭时的恢复使用同一状态机,避免额外手写
padding-right与浏览器预留空间叠加。内部弹窗滚动区独立配置。 - 兼容和 RTL。 现代浏览器支持后直接使用逻辑内联边缘;旧环境保留最小化回退,并按方向、滚动条位置和安全区检查视觉结果。
- 量化效果。 使用
layout-shift性能条目记录位移,区分用户输入前后的 CLS,结合实验室长列表、弹窗和网络慢场景以及真实用户 p75 数据。CLS 的良好目标是 p75 不超过 0.1。
高质量示例回答
我会把声明放在真实拥有滚动的盒子上:
html {
scrollbar-gutter: stable both-edges;
}
.results-pane {
overflow: auto;
scrollbar-gutter: stable;
}stable 让经典滚动条的预留空间在无溢出时也存在;both-edges 让视口两侧保持对称。若系统使用覆盖式滚动条,滚动条本来就不占布局空间,因此不能把该属性当成固定宽度方案。打开弹窗时我不会再无条件追加滚动条宽度补偿,而是让页面锁定逻辑与 gutter 策略协同;弹窗内部滚动区单独配置。
我会检查根元素与 body 的实际效果、嵌套滚动容器、RTL、关闭弹窗后的恢复、旧浏览器回退和减少动画偏好。验证同时采集 layout-shift 条目与现场 p75 CLS,目标是 p75 CLS 不超过 0.1。MDN 与 W3C 规范用于属性语义,web.dev 用于 CLS 诊断。
常见错误
- 把
scrollbar-gutter写在普通父容器上,却没有确认哪个元素真的滚动。 - 认为
body的声明必然控制视口,忽略根元素和浏览器特殊处理。 - 在覆盖式滚动条上承诺固定的像素占位。
stable与手写padding-right同时启用,弹窗打开后出现双重空白。- 只在无 RTL、单一操作系统的截图中验收,没有测量 CLS 或内部滚动面板。
追问与回答
为什么需要 both-edges?
单侧 stable 只预留滚动条所在的内联边缘。内容区域若以视口中心对齐,另一侧也增加等宽 gutter 才能保持左右几何对称;最终仍应在 RTL 和不同滚动条位置上实测。
scrollbar-gutter 能解决弹窗滚动锁定的所有问题吗?
不能。它处理滚动盒的布局预留,不负责焦点陷阱、背景交互、滚动位置恢复或弹窗层级。锁定状态机仍需独立验证,并避免与手写宽度补偿重复。
如何测试覆盖式与经典滚动条?
在至少一套经典滚动条环境和一套覆盖式滚动条环境中,分别测试无溢出、出现溢出、打开关闭弹窗、内部面板滚动、RTL 和缩放。记录关键元素的几何位置与 layout-shift 条目,而不只依赖肉眼截图。