touch-action 用于防误判而非修复卡顿,可消除300ms延迟、避免滚动冲突与穿透,但需正确设置位置和值;pan-y 失效主因是容器缺乏纵向滚动能力或被父级覆盖;禁用iOS弹性回弹须配合 passive: false 的 touchmove + preventDefault;遮罩层下页面滚动应精准拦截非可滚动区域;will-change 与 touch-action 滥用反致卡顿,须动态添加并作用于实际位移元素;touch-action 不继承,子元素交互需单独声明。

直接结论:touch-action 不是用来“修”卡顿的,而是用来“防误判”的。它解决不了重绘回流导致的掉帧,但能砍掉 300ms 手势判定延迟、避免滚动冲突、防止滑动穿透——前提是设对位置、设对值。
touch-action: pan-y 为什么加了反而纵向滚不动?
这不是 bug,是浏览器按声明严格执行的结果。当你在某个容器上写了 touch-action: pan-y,浏览器就在 touchstart 阶段锁定了“只响应垂直位移”,后续所有横向偏移都会被忽略;但如果这个容器本身没设置 overflow-y: auto 或内容未溢出,用户划一下根本触发不了原生滚动,手指一松就卡住。
- 必须确保该容器有明确的纵向滚动能力(比如设置了
height+overflow-y: auto) - 父级不能同时设了
touch-action: none或manipulation,否则子元素的pan-y会被覆盖 - 嵌套滚动时(比如弹窗里有个长列表),
pan-y要加在列表容器自身上,而不是弹窗根节点——否则外层截断事件,内层收不到touchmove - Android 某些定制系统(华为 EMUI、小米 HyperOS)对
pan-y响应偏慢,尤其配合transform动画时,建议真机验证
touch-action: none 导致 iOS 弹性回弹还在,怎么彻底禁用?
只给 很多人以为加了 最常被忽略的一点:touch-action 不继承,子元素要点击就得单独加 touch-action: none 确实会禁掉滚动和缩放,但它不碰「弹性滚动」(overscroll bounce)这个物理反馈行为。iOS Safari 就算你把 touch-action: none 写死在
touchmove 事件中调用 e.preventDefault()
{ passive: false },否则 Chrome 和 iOS 14+ 会无视 preventDefault
document 上,只绑在你要锁定的那块区域(比如画布、游戏区)touch-action: none 响应极慢甚至无效,真机测试不可跳过弹窗遮罩层下页面还在滚?别乱加 overflow: hidden
body 加 overflow: hidden 在多数安卓机上无效,真机上照样能拖;而加 position: fixed 虽然能锁住,但会强制 body 回滚到顶部——这是个副作用,不是 bug。
touchmove,用 e.target.closest('.scrollable') 判断是否点在可滚动子区域里.scrollable 区域内时,才调 e.preventDefault()
textarea、长列表等可滚动区的正常交互touchmove 并无差别 preventDefault,否则弹窗里所有滚动都废了touch-action 和 will-change 一起用,为什么更卡?
touch-action: pan-y 再配个 will-change: transform 就是“双保险”,结果 iOS Safari 卡顿、Android Chrome 掉帧。这是因为 will-change 提前把元素挪进独立图层,反而加重了合成器负担——尤其当页面存在多个该属性或频繁重排时。
will-change 应只对“正在被 touchmove 驱动的元素”动态添加,滑动结束 100ms 后立刻移除.list-wrapper)上,优先作用于实际位移的子元素(如 .list-content)touch-action 是前提:没有它,will-change 单独用几乎无效;浏览器仍会等 300ms 判定手势意图overflow: hidden + border-radius,这会让浏览器强制回退到软件渲染touch-action: manipulation;轮播图里一个按钮点了没反应,大概率不是 JS 问题,而是这个属性被父级的 pan-x 给盖掉了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











