-webkit-overflow-scrolling: touch 已废弃且在 iOS 13+ 完全失效,现代 WebKit 默认启用原生惯性滚动,添加该属性反而引发卡顿、fixed 错位等问题;真正有效的优化是合理使用 will-change、transform 触发合成层,设置显式高度,并为 touchmove/scroll 事件添加 passive: true。

-webkit-overflow-scrolling: touch 已失效,新项目必须移除
它在 iOS 13+ 完全不生效,iOS 8 起就被标记为废弃;现代 WebKit(Safari 16+、iOS 15+ WebView)默认启用原生惯性滚动,加这句反而容易引发卡顿、fixed 元素错位、下拉刷新失灵等问题。
为什么加了 -webkit-overflow-scrolling: touch 还是卡
不是属性写错了,而是它被其他样式或行为“抵消”了。这个属性只在极窄的兼容窗口内起作用:必须同时满足「有明确 height/max-height」「position: static(或未触发新层叠上下文)」「内容真实溢出」三个条件。
- 父容器用了
position: fixed或transform,子滚动区高度计算异常 - 高度靠 JS 动态撑开(比如
innerHTML插入后才设高),合成层没及时创建 - 容器设置了
overflow-y: auto,但内容实际没超出,iOS 不会激活 touch 滚动回弹 - 外层用了
filter、opacity: 0.99、mask等强制重绘属性,间接禁用原生滚动加速 - 监听了
touchmove并无条件调用e.preventDefault()—— 浏览器直接交出滚动控制权,该属性彻底失效
真正有效的滚动优化 CSS 组合
重点不是加 hack,而是让浏览器把滚动容器识别为独立合成层,并避免触发重排重绘。
- 给滚动容器加
will-change: scroll-position:仅对明确需要优化的容器(如.scroll-container)使用,提前提示浏览器准备合成层;iOS 15+ 才稳定,旧版无效 - 必要时加
transform: translateZ(0)或transform: translate3d(0, 0, 0):适用于 iOS 12–15 中部分未自动合成的场景;注意它会创建新 stacking context,可能影响z-index和遮罩逻辑 - 确保容器有显式
height或max-height(不能是min-height或靠内容撑开) - 移除所有干扰属性:避免在滚动容器及其祖先上使用
filter、opacity 、<code>backdrop-filter
scroll/touchmove 事件必须配 passive: true
这是最常被忽略、效果最立竿见影的优化点。不设 { passive: true },浏览器会阻塞滚动等待 JS 执行完毕,导致掉帧甚至手势延迟。
- 必须加的事件:
touchstart、touchmove、scroll(尤其是 overflow 容器内的 scroll) - 正确写法:
el.addEventListener('touchmove', handler, { passive: true }) - 错误写法:
el.addEventListener('touchmove', handler, true)(这是useCapture,不是 passive) - 如果真要阻止默认行为(如下拉刷新),只在目标区域绑定
{ passive: false },并用e.cancelable判断后再调用e.preventDefault()
滚动流畅的核心从来不是某个 CSS 属性,而是合成层是否就位、主线程是否被同步读取阻塞、事件是否被浏览器信任。现在加 -webkit-overflow-scrolling: touch 就像给电动车装马达——不仅多余,还可能烧控制器。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











