全屏滚动应优先使用 CSS scroll-snap-type 与 scroll-snap-align 实现,Safari 13.1 前需补 scroll-snap-stop: always;禁用 overscroll-behavior 防橡皮筋,用 IntersectionObserver 监听页面切换,避免 JS 模拟滚动性能问题。

全屏滚动依赖 scroll-snap-type,但 Safari 旧版本不认 scroll-snap-align
现代 CSS 全屏滚动的核心是 scroll-snap-type + scroll-snap-align,不是靠 JS 模拟。但 Safari 13.1 之前对 scroll-snap-align 支持极差——哪怕写了 scroll-snap-align: center,实际滚动仍会停在顶部,且无报错。
- 必须给容器设
scroll-snap-type: y mandatory(或x),不能只写proximity,否则 iOS 上大概率失效 - 每个子区块要加
scroll-snap-align: center,同时确保其高度为100vh(不能用min-height或弹性撑高) - Safari 12–13.0 需补
scroll-snap-stop: always到子项上,否则可能跳过某一页 - 避免父容器有
overflow: hidden或transform,这会切断 scroll-snap 的捕获链
scroll-behavior: smooth 在 Chrome/Firefox 有效,但 iOS Safari 完全忽略
iOS Safari(包括最新版)至今不支持 scroll-behavior: smooth,设了也白设。想在移动端实现平滑滚动,只能退回到 scrollIntoView({ behavior: 'smooth' }) 或用 requestAnimationFrame 手动插值——但后者要自己处理惯性、加速和边界阻尼。
-
scrollIntoView在 iOS 上虽支持behavior: 'smooth',但仅限于元素可见时;如果目标页被display: none或visibility: hidden过,会直接跳转 - 用
scrollTop+requestAnimationFrame实现时,别直接用element.offsetTop算位置——它不含margin-top和transform偏移,得用getBoundingClientRect().top + window.scrollY - 若页面有 sticky header,记得在计算目标位置时减去 header 高度,否则滚动终点会偏高
滚动监听用 IntersectionObserver,别用 scroll 事件
监听当前页变化,scroll 事件在快速滚动时会丢帧、触发延迟,且频繁重排导致卡顿;IntersectionObserver 是唯一可靠方案,连 iOS Safari 11+ 都支持。
- 观察器需设
rootMargin: '0px 0px -50% 0px',让阈值落在视口垂直中线,避免上下页同时触发 - 不要在
callback里调scrollTo或修改 DOM,容易引发循环:滚动 → 触发 observer → 修改 → 再滚动 - 如果用
pageYOffset做 fallback,注意它返回的是小数(如123.456),比较时别用===,改用Math.round()或误差容忍判断
移动端真机调试时,overscroll-behavior 必须关掉弹性回弹
iOS 和 Android 浏览器默认允许内容滚动到底后继续拖拽产生“橡皮筋”效果,这会让全屏滚动页在首尾页出现意外位移,破坏 snap 行为。必须显式禁用。
立即学习“前端免费学习笔记(深入)”;
- 在滚动容器上加
overscroll-behavior: none,不是contain——后者在某些安卓 WebView 下无效 - 若容器是
body,需同时设html { overscroll-behavior: none },因为部分浏览器把根滚动归到html - 禁用后,iOS 上手指快速甩动仍可能触发微弱回弹,这是系统级行为,无法彻底消除;可接受的折中是加
touch-action: pan-y抑制横向误触
will-change 就能让滚动掉帧。










