最近在做后台项目(带路由切换动画)的时候,遇到一个挺烦人的问题:页面切换时右侧滚动条会闪一下,还伴随着轻微的布局抖动,看起来很不舒服。
这里简单记录下现象、原因和最终解决方式。
一、问题描述
场景大概是这样:
- 左侧菜单切换页面
- 右侧用
<router-view> - 有加 transition(淡入淡出 + 一点位移)
然后就会出现:
- 页面切换瞬间,右侧会闪出一根滚动条
- 很快又消失
- 在 Windows 下尤其明显(页面会左右抖一下)
二、原因
其实本质就是一句话:
页面切换过程中,高度在短时间内不稳定,触发了滚动条
具体有几个常见触发点:
1. 动画带来的"临时高度变大"
比如写了:
css
transform: translateY(6px);
动画执行时,页面会被"往下挤"一点点。
如果本来刚好撑满屏幕,这 6px 就会让容器"超高",浏览器就会临时加个滚动条。
动画结束 → 高度恢复 → 滚动条消失 → 就变成"闪一下"。
2. mode="out-in" 导致的高度塌陷
流程是这样的:
-
旧页面先销毁
-
中间会有一瞬间容器是空的(高度≈0)
-
新页面再挂载
这一收一放,很容易触发浏览器反复计算高度 → 滚动条反复出现。
3. Windows 滚动条会"占位置"
这个也很关键:
-
Windows 滚动条是占宽度的(大概 15px)
-
出现/消失时会把页面内容"挤来挤去"
所以会看到明显的左右抖动。
三、我试过但不太行的方法
踩过几个坑,简单说下:
- 去掉动画: 能缓解,但不想这么干
- scrollbar-gutter: stable: 只能防抖动,闪烁还在
- 给页面写死高度: 不太通用,表格/列表会很难受
四、最终解决方案(推荐)
核心思路就一句话:
外层不允许滚动,滚动交给内部自己处理
1.外层容器禁止滚动
css
.sys-page {
flex: 1;
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
}
效果:
-
外层永远不会出现滚动条
-
动画再怎么"抖",也不会影响到外层
2. 内部组件自己滚
比如页面里的内容区:
css
.data-content {
flex: 1;
min-height: 0;
overflow-y: auto;
}
这样:
-
真正需要滚动的地方才滚
-
不会影响整个页面结构
五、总结
这次问题本质不是 Vue,也不是 Router,而是:
布局 + 动画 + 滚动机制叠加导致的副作用
解决关键就两点:
-
外层:overflow: hidden,彻底隔离
-
内部:谁需要滚动谁自己处理
改完之后:
-
滚动条不闪了
-
页面也不抖了
-
结构也更清晰了