scroll-snap-type 必须作用于显式可滚动容器,直接设在 html 或 body 上几乎无效;正确做法是创建 height: 100vh、overflow-y: scroll、scroll-snap-type: y mandatory 的包裹层,并确保每个 section 设 height: 100vh 与 scroll-snap-align: start/center。

scroll-snap-type 必须作用在显式可滚动容器上
直接给 body 或 html 加 scroll-snap-type: y mandatory 几乎总失效,因为浏览器默认滚动由 html 承担,但它常被视口撑满、无内容溢出,scroll-snap 就不会触发。
正确做法是新建一个包裹层:
- 用
<div class="scroll-container"> 包住所有 <code>section -
.scroll-container必须设height: 100vh(不能用min-height)、overflow-y: scroll、scroll-snap-type: y mandatory -
html, body加margin: 0; padding: 0; height: 100%,防止外边距干扰尺寸计算 - 每个
section必须设height: 100vh(垂直)或width: 100vw(水平) - 必须配
scroll-snap-align: start(顶部对齐)或center;只写scroll-snap-align不加值无效 - 禁用
margin-top/margin-bottom,它会改变offsetTop,导致视觉停靠位置偏移 - 在滚动容器上加
overscroll-behavior-y: contain,彻底禁用纵向回弹 - 横向滚动(如相册)必须加
touch-action: pan-x,否则 iOS 会默认锁死横向滑动 - 不要在滚动容器内监听
touchstart或touchmove,哪怕空回调也会触发 passive event warning,拖慢滚动帧率 - Chrome/Edge:
.scroll-container::-webkit-scrollbar { display: none; } - Safari:
.scroll-container { -webkit-overflow-scrolling: touch; }+ 配合overscroll-behavior-y: contain - 别指望
scrollbar-width: none在 Safari 生效,它只在 Firefox 有效
每个 section 必须显式声明尺寸与对齐方式
scroll-snap-align 不是“建议对齐”,而是强制停靠点。如果 section 高度不固定、被 flex 拉伸、或依赖内容自适应,浏览器无法确定停在哪,就会跳过 snap 或错位。
移动端必须处理 overscroll-behavior 和 touch-action
iOS Safari 默认开启弹性回弹(overscroll),滚动到底部时拉出空白再回弹,不仅破坏沉浸感,还会让 window.scrollY 在回弹阶段返回异常值,干扰 JS 判断逻辑。
隐藏滚动条要分浏览器写死
Chrome/Edge/Safari 下,scroll-snap 容器的滚动条默认可见,且会占位——即使设了 display: none,仍可能造成内容轻微偏移。
最容易被忽略的是:所有 scroll-snap 行为都依赖“可滚动容器有明确溢出”,而不是“看起来像在滚动”。很多问题不是 CSS 写错了,而是容器根本没被浏览器识别为可滚动目标。











