写过前端的人都踩过这个坑——弹窗一出来页面抖一下,今天 CSS 一行把这件事彻底原生化了
写过前端人都踩过这个坑——弹窗一出来页面抖一下,今天 CSS 一行把这件事彻底原生化了
打开一个 Modal、侧边栏、搜索浮层,页面滚动条突然消失,整个页面往右跳了几像素。关掉弹窗,又跳回去。这个体验问题,几乎每个前端项目都存在,大家也都知道,但每次修都要在 JS 里写一段测量滚动条宽度再注入 padding 的样板代码,而且这段逻辑容易在多个控制器之间漂移,时间久了修法反而比问题本身更乱。
现在浏览器原生支持了,一行 CSS 就能从根上消除这个布局抖动。
scrollbar-gutter: stable 是 CSS Overflow Module Level 3 里的属性,它的核心逻辑很简单:无论滚动条当前是否可见,提前把滚动条那条轨道的宽度预留出来。这样当 overflow: hidden 隐藏滚动条时,预留的空间还在,布局宽度不变,页面不跳。
过去业界有两个变通方案。第一个是 overflow-y: scroll,让滚动条永远显示,短页面也显示,体验很差。第二个是量出滚动条宽度(比如 window.innerWidth - document.documentElement.clientWidth),然后在 body 上动态加对应像素的 padding-right。这个方案脆弱的地方在于:测量发生在运行时,弹窗打开到 padding 注入之间必然存在至少一帧的抖动;而且这个逻辑散落在每个控制弹窗打开关闭的地方,一旦有一处漏了,就会跳。
用 scrollbar-gutter: stable 之后,这段历史债务可以一次性清理掉:
html {
scrollbar-gutter: stable;
}
这行声明告诉浏览器:滚动条那条沟永远给我留着。不管内容有没有溢出、弹窗有没有打开,页面宽度不变。
如果你页面有弹窗背景是 position: fixed; inset: 0 全屏覆盖的,有一个小问题需要注意:滚动条沟在布局视口外面,inset: 0 只铺到内容边缘,全屏背景会在右边留下一条细边。这个时候要么接受那条细边,要么还是要在弹窗打开时手动处理背景层的宽度——但至少,页面主体内容的抖动问题已经解决了,样板代码少写了好几处。
兼容性已经不再是障碍:Chrome 94+、Firefox 97+、Safari 15.4+,全球覆盖率约 90%,和 color-mix()、@property 这些你已经在用的特性是同一批浏览器。如果你的项目已经在用 CSS 自定义属性或者 OKLCH 颜色,上这个属性完全没压力。
下一步很简单:打开你的 html 标签或者 body 样式,加一行 scrollbar-gutter: stable,然后把项目中所有量滚动条宽度、动态加 padding 的代码搜出来,能删的删——那些都是可以退休的技术债。
评论区
登录后可评论。