移动端长列表卡顿的关键是减少浏览器无用功:用虚拟滚动控制渲染量(如RecycleScroller)、慎用will-change(仅设于滚动容器并配transform)、content-visibility配合contain-intrinsic-size提速首屏、iOS需适配弹性滚动。

移动端长列表滚动卡顿,核心不是“怎么动得更快”,而是“别让浏览器做无用功”。关键在控制渲染量、减少重排重绘、避免GPU过载——这些比调样式属性更底层、更有效。
只渲染可见区域:虚拟滚动是首选
1000 条数据全塞进 DOM,中低端机内存直接飙到 200MB,帧率掉到 20fps 以下。虚拟滚动只保留当前可视区 + 少量缓冲区(比如 5~8 项)的 DOM 节点,实测 DOM 数量从上千降到二三十,内存压到 60MB 左右,FPS 稳定在 55~60。
- 固定高度场景(如商品卡片、新闻条目)优先用 RecycleScroller 或 Swiper 的
virtual: true模式,性能最优,无需测量 - 高度不固定(含多行文字、图片加载中)选 DynamicScroller 或配合
getBoundingClientRect()缓存高度,首次滑入后复用,避免反复测量 - 切忌把虚拟滚动当“开关”一开了事:必须设置
item-size或预估contain-intrinsic-size,否则滚动条跳变、内容上蹿下跳
慎用 will-change,别给 GPU 塞满图层
will-change: transform 不是“加速油门”,而是“请浏览器提前准备合成层”。写在每个列表项上,等于告诉 GPU:“这 20 个元素都要单独开图层”——中低端安卓机显存扛不住,纹理上传阻塞,反而更涩。
- 仅对真实滚动容器设,比如
.list-container(有明确 height + overflow-y: auto)或虚拟滚动的.scroll-content - 必须搭配真实 transform 变化,哪怕只是
transform: translateZ(0),否则浏览器直接忽略 - DevTools Layers 面板里图层数 > 8 就要立刻排查,
will-change: scroll-position完全不用,iOS Safari 不支持
用 content-visibility 提速首屏,但必须配占位高度
移动端视口小,1000 条里真正可见的通常就 3~5 个。content-visibility: auto 让浏览器跳过离屏项的 layout 和 paint,首屏渲染从 800ms 降到 200ms,内存下降超 70%。
- 必须设
contain-intrinsic-size:固定高卡片写120px,含两行文字+头像写160px,宁大勿小 - 严禁写
0或留空,这等于没设;也不能依赖子元素的height,它优先级更低 - 和
display: none别混用:content-visibility: auto保留占位、支持聚焦、无障碍友好
iOS 弹性滚动要主动适配,不是加个属性就完事
iOS 的“橡皮筋”效果在虚拟滚动里容易触发空白闪现、重复加载。单纯加 -webkit-overflow-scrolling: touch 不够,得配合行为兜底。
- 容器必须设
height或max-height,不能靠内容撑开,否则弹性回弹时计算错乱 - 监听
scroll事件时用{ passive: true },避免触摸阻塞;触底判断改用scrollTop + clientHeight >= scrollHeight - 20,留出弹性缓冲 - 滚动中临时隐藏图片、复杂组件,静止后再恢复,减少绘制压力


















