ios safari滚动卡顿的根本原因是未创建独立合成层且未激活原生滚动事件链,必须同时满足:确定高度(height/max-height)、启用will-change或transform、设置touch-action、touchmove/scroll事件加passive: true。

滚动不流畅根本不是overflow:auto写错了
写了overflow-y: auto却卡顿,90%的情况不是属性没生效,而是浏览器压根没把它当“可滚动区域”处理——它没创建独立合成层,也没激活原生滚动事件链。iOS Safari 尤其敏感:哪怕只差一个height或漏了{ passive: true },都会退回到软件渲染,帧率掉到 20fps 以下。
必须设 height 或 max-height,且父级高度要确定
滚动容器没高度,子内容再长也溢不出去,iOS 就不会启用惯性滚动上下文。常见陷阱是:min-height、百分比高度(如height: 100%)在父级没明确高时完全无效。
-
html, body { height: 100% }必须写,否则height: 100%的子容器算出来是 0 - 用
max-height比height更安全,避免内容少时留白过大 - 实在不确定高度,可用
height: calc(100% + 1px)强行触发溢出判定
-webkit-overflow-scrolling: touch 已失效,删掉它
这个属性在 iOS 15.4+ 和 Safari 16+ 中不仅不生效,还会引发fixed错位、下拉刷新失灵、滚动掉帧。你看到“加了更卡”,不是配置错,是浏览器正在努力忽略它。新项目里必须删干净。
真正起作用的是:
-
will-change: scroll-position(iOS 15+ 稳定,旧版无效) -
transform: translateZ(0)(兼容 iOS 12–15,但单独用不够,需配合overflow-y: auto) -
touch-action: pan-y(垂直滚动)或pan-x(横向),禁用默认手势冲突
touchmove 和 scroll 事件没设 passive: true
这是最常被跳过、效果却最立竿见影的一环。只要监听了touchmove却没传{ passive: true },浏览器就得暂停滚动等 JS 执行完,直接导致手势延迟甚至卡顿。
- 错误写法:
el.addEventListener('touchmove', handler) - 正确写法:
el.addEventListener('touchmove', handler, { passive: true }) - 同理,
scroll事件也要加{ passive: true },尤其在监听滚动位置做懒加载时
复杂点在于:这些条件要同时满足——高度确定、合成层建立、事件不阻塞、祖先没filter或opacity: 0.99。少一个,iOS 就可能退回低效路径。别指望单靠某个 CSS 属性解决问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











