页面抖动主因是滚动条显隐导致宽度突变或频繁读写offset类属性引发布局抖动;加html{overflow-y:scroll}可锁定宽度消除抖动,但会常驻滚动条。

页面抖动不是 JS 报错,也不是浏览器崩溃,而是视觉上「一卡一跳」「滚动时晃一下」「切换路由后内容偏移」——大概率是滚动条出现/消失导致的宽度突变,或 JS 频繁读写 offset 类属性引发的布局抖动(layout thrashing)。
为什么加 html, body { overflow-y: scroll; } 就不抖了
根本原因是:滚动条宽度(通常 12–17px)在有无内容溢出时动态出现/隐藏,导致 body 可用宽度突变,所有水平居中、width: 100% 或 flex 布局元素瞬间重排。
强制始终显示垂直滚动条,就锁死了可用宽度,消除了这个突变源。
- 只对
html设置overflow-y: scroll即可,body不必重复设(避免双滚动条) - Chrome/Firefox/Safari 均支持,但 Safari 在某些 zoom 场景下可能仍微调,可加
html { margin-left: -webkit-scrollbar; }补偿(极少需) - 副作用是滚动条常驻,若设计不允许,应改用「隐藏全局滚动条 + 局部滚动容器」方案
getBoundingClientRect() 调用太勤会真卡住主线程
这不是“看起来卡”,而是性能实锤:每次调用 getBoundingClientRect()、offsetHeight、scrollLeft 等,浏览器都必须同步触发重排(reflow),若在 scroll 或 resize 回调里反复读写,就会 layout thrashing。
立即学习“前端免费学习笔记(深入)”;
- 滚动监听中,把所有尺寸读取放在开头一次性做完:
const rect = el.getBoundingClientRect(); const { top, height } = rect; - 避免在循环里对多个元素依次读
offsetTop—— 改用document.querySelectorAll(...).forEach先 collect 所有元素,再统一读 - 写样式时别逐个设
el.style.top = '10px'; el.style.left = '20px';,改用el.style.cssText = 'top:10px;left:20px;'或Object.assign(el.style, { transform: 'translateY(50px)' })
fixed 定位元素嵌套在 scroll-view 或局部滚动容器里必抖
微信小程序的 scroll-view、Vue 的 el-scrollbar、甚至自定义 overflow: auto 容器中,内部设 position: fixed 会导致定位基准错乱:它本该相对于视口,却被截断在局部滚动上下文里,浏览器不断尝试修正位置,表现为高频跳动。
- 把
position: fixed元素全部移出滚动容器,挂到body下 - 用
position: sticky替代部分场景(注意兼容性:IE 不支持,iOS Safari - 若必须保留在容器内,改用
transform: translateY()模拟固定效果,配合requestAnimationFrame同步滚动偏移
真正难处理的不是你写的那几行 CSS 或 JS,而是第三方组件库在 mounted 或 onShow 里偷偷调用 clientHeight,又没做防抖或批量读取。这时候得靠 Chrome DevTools 的 Performance 面板录一段滚动操作,看 Layout 事件是否密集爆发——抖动从来不是单一原因,而是多个“看似无害”的读写叠加成的雪崩。



















