局部滚动卡顿是因浏览器未将overflow: scroll容器识别为独立可滚动图层,需同时加-webkit-overflow-scrolling: touch和transform: translateZ(0),并设明确高度,否则仍卡顿。

局部滚动卡顿不是“样式没调好”,而是浏览器没把那个 overflow: scroll 容器识别为独立可滚动图层——只要它存在且内容超一屏,风险就已触发,和有没有写 JS 无关。
为什么加了 overflow: scroll 还是卡
浏览器默认不给 overflow: scroll 容器开硬件加速。它走的是 CPU 软件合成,帧率掉到 20–30fps,尤其在低端安卓 WebView 或 iOS Safari 下更明显。
- 必须同时加两行 CSS:
-webkit-overflow-scrolling: touch(iOS 必开,安卓 WebView 也认) +transform: translateZ(0)(强制创建合成层) - 只加其中一条,比如只加
translateZ(0),多数中低端安卓机仍会卡 - 容器高度必须明确(不能是
height: auto或靠 JS 动态撑开),否则合成层可能被降级 - 别对整个
加overflow: scroll,限定在具体容器,如scroll事件一监听就卡的真正原因桌面 Chrome 每秒可触发 60+ 次
scroll,移动端更密集。每次回调若读取scrollTop、调用getBoundingClientRect()或改style.transform,都会触发强制同步布局(forced synchronous layout),单次耗时轻松超 10ms。- 必须加
{ passive: true }:否则 Chrome 会等 JS 执行完才滚动,控制台报 “Unable to preventDefault inside passive event listener” 就是没加 - 节流别只靠
setTimeout:推荐requestAnimationFrame+ 标志位,或requestIdleCallback做延迟响应 - 读位置优先用
element.scrollTop(比window.scrollY少一次跨文档查询) - 避免在回调里反复读同一元素的
offsetTop、clientHeight等,会强制回流
移动端滑动不跟手、没惯性、松手就停
这不是“动画不够顺”,而是原生滚动机制被破坏了。常见于绑了
touchmove监听器却没设passive: true,或用了-webkit-overflow-scrolling: touch却没配好上下文。-
touchmove监听器必须显式传{ passive: true },哪怕里面只写console.log() - 如果真要拦截滚动(如下拉刷新),改用
touchstart+touchmove组合,并只在必要时设passive: false -
-webkit-overflow-scrolling: touch在 iOS 12–14 有已知缺陷:开启后弹性系数被削弱,松手后减速过快、回弹距离变短 - 安卓 WebView 中,若
layerType="software"被硬编码,CSS 合成层会完全失效;需确认webView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
长列表超过 200 行,光靠 CSS 优化没用
DOM 节点过多会压垮渲染线程,不是逻辑慢,是内存和遍历成本太高。虚拟滚动不是“可以考虑”,是硬性需求。
- 只渲染视口内 + 上下各缓冲 1~2 屏的节点(通常 ≤ 20 条)
- 用一个占位 撑起总高度:
style="height: calc(var(--item-height) * var(--total-count))"scroll回调里只更新scrollTop和当前渲染起始索引,不新增/删除 DOM- 慎用
will-change: scroll-position:iOS 15+ 才稳定,旧版无效;长期挂着会导致纹理泄漏最容易被忽略的是:合成层是否真的生效。打开 Chrome DevTools → Rendering → 勾选 “Layer Borders”,滚动时看容器有没有绿色边框——没有,说明优化还没真正落地。
- 必须加
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











