现象
站点在新启动后,第一次从首页点击 About 或 Archive 时,页面会整体向左偏移一点。第一次触发之后,后续再点同类页面就不会再抖。
这个问题的特征很明确:
- 不是每次切页都发生
- 只在首次导航时出现
- 视觉上像是页面宽度瞬间变了
第一反应
这种“横向偏移一下”的问题,第一反应通常是滚动条宽度变化:
- 当前页有滚动条,目标页没有滚动条
- 或者某个脚本在首次导航时才真正接管滚动容器
所以排查从这两类地方开始:
- 全局滚动条占位
Swup切页逻辑OverlayScrollbars是否接管了body
实际原因
这次不是单点问题,而是几个因素叠在一起:
1. 页面级滚动条在首次导航时切换状态
原来布局里对整页启用了 OverlayScrollbars(body)。这类库如果接管的是整个页面,而不是局部容器,就很容易在首次真正初始化时替换原生滚动条,从而导致页面宽度发生一次变化。
这正好解释了为什么:
- 第一次点
About/Archive会偏移 - 之后就稳定了
因为“接管动作”只发生一次。
2. 切页时还有一个临时的页面增高补丁
布局里原本还有一个 page-height-extend 元素,在 visit:start 到 visit:end 期间会把页面临时拉高,目的是防止切页滚动动画跳动。
这个补丁会影响页面在切换期间的滚动状态,也会放大滚动条相关的抖动问题。
3. 一部分全局样式是在运行时脚本里导入
OverlayScrollbars 和 PhotoSwipe 的样式原来是在 <script> 里导入的。开发模式下,首次导航时样式可能刚好才完成注入,于是页面首跳更容易出现一次性布局抖动。
最终修复
最后用了几步一起收口:
固定根滚动条占位
在根布局里加上:
html { overflow-y: scroll; scrollbar-gutter: stable;}这样即使页面内容高度变化,滚动条槽位也不会突然出现或消失。
不再让 OverlayScrollbars 接管整个 body
保留局部滚动区域的自定义滚动条,但去掉页面级 OverlayScrollbars(body)。
这是这次修复里最关键的一步。
去掉切页期间临时增高页面的补丁
删除 page-height-extend 和对应的 Swup 钩子逻辑,避免切页过程中人为改变页面滚动状态。
把全局样式提前到 Astro 前置导入
把:
overlayscrollbars/overlayscrollbars.cssphotoswipe/style.css
从运行时脚本里移到布局文件的前置导入区,让它们在页面首屏就已经是稳定状态。
这次改动的结论
这种“只在第一次切页时偏一下”的问题,通常不要只盯着某一段动画代码。
更高概率的根因是:
- 页面级滚动容器被首次初始化
- 滚动条是否占位发生变化
- 全局样式在首次导航时才真正生效
如果项目里同时用了页面过渡、滚动条美化、运行时样式注入,这类问题尤其容易出现。
最后验证
修完后重新执行:
pnpm checkpnpm build然后重启开发服务器,从首页第一次点击 About 和 Archive 验证。
这次在完成上述调整之后,首次导航的横向偏移已经消失。