应移除已废弃的 -webkit-overflow-scrolling: touch,其在 iOS 15.4+/Safari 16+ 中不仅无效,反而导致 fixed 错位、下拉刷新失灵和掉帧;卡顿主因是容器高度未明确、祖先层截断滚动上下文、事件监听器缺 passive: true 等。

别再加 -webkit-overflow-scrolling: touch —— 它在 iOS 15.4+ 和 Safari 16+ 中已废弃,加了反而引发 fixed 错位、下拉刷新失灵、滚动掉帧。
为什么加了 -webkit-overflow-scrolling: touch 还是卡
这不是写法不对,而是浏览器根本不再响应这个声明。它现在只是个“干扰项”,甚至会阻断合成层创建流程。真正卡顿的根源是:
- 滚动容器高度未明确(比如用
height: auto或靠 flex 内容撑开) - 父级或祖先用了
position: fixed、transform、filter或opacity: 0.99,导致滚动上下文被截断 -
touchmove或scroll事件监听器没设{ passive: true },浏览器被迫同步等待 JS 执行 - 子内容实际未溢出(
scrollHeight ),iOS 根本不激活惯性滚动
必须配齐的三要素(iOS 15+ 稳定生效)
只写一个属性没用,以下三项要同时满足:
- 滚动容器设**确定高度**:
height、max-height或100dvh(别用100vh,地址栏展开时会跳变) - 确保父级有确定高度,例如:
html, body { height: 100% };Flex 容器中父项需加min-height: 0 - 显式提示合成层:
will-change: scroll-position(iOS 15+ 支持良好,旧版无效,不滥用) - 移除所有干扰项:滚动容器及其任意祖先不能有
filter、backdrop-filter、mask或opacity
touchmove 和 scroll 事件必须加 { passive: true }
这是最常被跳过、效果却最立竿见影的一环。不加它,iOS Safari 会暂停滚动等待 JS 回调返回,直接造成手势延迟甚至冻结:
立即学习“前端免费学习笔记(深入)”;
- 错误写法:
el.addEventListener('touchmove', handler) - 正确写法:
el.addEventListener('touchmove', handler, { passive: true }) - 同理适用于
scroll:el.addEventListener('scroll', handler, { passive: true }) - 若需在特定条件下阻止默认行为(如拖拽排序),改用
{ passive: false },并仅在必要时调e.preventDefault()
容易被忽略的边界细节
即使上述都做了,仍可能卡在几个隐蔽点上:
-
overscroll-behavior-y: contain只防穿透,不解决卡顿 —— 它和流畅度无关,别指望它“顺便修好滚动” - 动态插入内容后才设置容器高度(比如
innerHTML + el.style.height),浏览器来不及触发层提升,建议先设高再塞内容 - 用了
100dvh但运行在 iOS 16.4 以下?需 JS fallback 到window.innerHeight并监听 resize - 滚动容器内嵌了
iframe或svg?它们可能撑不开高度,加min-height: 1px强制触发溢出判定


















