不能单独靠overscroll-behavior解决卡顿;它只防滚动穿透,不激活惯性,iOS需配合-webkit-overflow-scrolling: touch(即使废弃仍强依赖)及明确高度、overflow声明才能启用原生滚动。

移动端滑动卡顿,不是“加个属性就能好”的问题,而是滚动上下文、硬件加速、平台特性三者没对齐。iOS 上尤其明显:手指一抬就停,像被钉住——这不是 CSS 写错了,是浏览器根本没启用原生惯性滚动。
为什么 -webkit-overflow-scrolling: touch 必须加
iOS Safari 从 5.0 起就把滚动行为拆成 auto 和 touch 两档,默认是 auto,即松手即停。只有显式设为 touch,系统才会接管并注入动能、弹性回弹和边界阻尼。
- 必须作用在**可滚动容器本身**上,且该容器需满足:
overflow-y: auto或scroll+ 明确高度(不能靠内容撑开) - Android Chrome 不认这个属性,但也不需要——它默认就带惯性;别为了兼容 Android 去删掉它
- iOS 17 仍强依赖此属性,哪怕官方已标为“deprecated”,删了就是丢惯性
overscroll-behavior: contain 能防穿透,但救不了卡顿
overscroll-behavior: contain 只解决“滚到边时会不会把事件传给父级”,比如弹窗滑到底,背后页面不动。但它不触发硬件加速,不激活 iOS 惯性,也不影响滚动帧率。
- 常见误操作:加了
contain后弹窗不穿透了,但滑起来还是“涩”——这说明惯性根本没起来,得回头检查-webkit-overflow-scrolling - 别用
none:它会干掉 iOS 弹性回弹和下拉刷新指示器,在 Edge 里还被当contain处理,行为不可控 - 生效前提:父容器不能是
overflow: hidden,Flex 布局中父项记得加min-height: 0,否则滚动流建不起来
Swiper 初始化后还是卡?检查 transform 触发条件
Swiper 默认用 transform: translateX() 做位移,但若没触发硬件加速,iOS 和低端 Android 就容易跳帧、掉帧。
- 给
.swiper-wrapper加一句transform: translateZ(0)或will-change: transform(注意只对活跃滚动容器加,别全局滥用) - 确保
.swiper-slide是块级元素,没被display: inline或浮动破坏文档流 - 如果用了自定义 class(如
my-swiper),JS 初始化时必须同步传container: '.my-swiper',否则 Swiper 找不到根容器,内部样式(包括touch-action: pan-y)全失效
100vh 在 iOS 上塌缩导致滚动失效
iOS 地址栏收起/展开会动态改变视口高度,用 height: 100vh 的滚动容器会跟着“抽搐”,高度瞬间变小,滚动上下文直接丢失,overscroll-behavior 和 -webkit-overflow-scrolling 全部失效。
- 优先改用
100dvh(iOS 16.4+ 支持),它响应视口真实可用高度 - 兼容老 iOS:用 JS 监听
resize,动态设style.height = window.innerHeight + 'px',并缓存避免频繁重排 - 别信“设了
viewport-fit=cover就万事大吉”——它只管安全区,不管视口高度抖动
真正卡顿的根源,往往藏在“滚动容器是否真正成立”这件事里:高度有没有、overflow 是否显式声明、父级是否截断了滚动流。这些比调哪个动画库都关键。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











