scroll-snap-type 必须作用于显式可滚动容器,即设置 overflow-y: scroll 且内容溢出、高度固定(如 100vh)的父元素,而非 body 或 html;子元素需设 height: 100vh 与 scroll-snap-align: start 才能精准吸附。

原生 CSS scroll-snap-type 是最轻量、最推荐的起点,但直接套在 body 或 html 上 99% 失效——问题不在写法,而在滚动容器没真正“可滚动”。
scroll-snap-type 必须作用于显式可滚动容器
浏览器只对设置了 overflow-y: scroll(或 auto)且内容实际溢出的元素应用 scroll-snap-type。而默认情况下,body 的滚动由 html 承担,html 又常被视口撑满、无溢出,导致 snap 完全不触发。
- 新建一个包裹层,比如
<div class="scroll-container">,并设 <code>height: 100vh; overflow-y: scroll; scroll-snap-type: y mandatory; -
scroll-container高度必须是固定值(100vh),不能用min-height或靠内容撑开,否则滚动高度不可控,snap 失效 -
html, body必须清空默认边距:margin: 0; padding: 0; height: 100%;,否则会干扰容器尺寸计算 - 每个
section必须设height: 100vh(垂直滚动)或width: 100vw(水平滚动);min-height仅作容错,不能替代 - 必须配
scroll-snap-align: start(顶部对齐)或center(居中对齐);只写scroll-snap-align不加值无效 - 禁止给
section设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; } - Firefox:
.scroll-container { scrollbar-width: none; } - Safari 16.4+ 支持
scrollbar-width: none,旧版只能靠padding-right+overflow: hidden模拟隐藏
每个 section 必须显式声明尺寸与对齐方式
scroll-snap-align 不是“建议对齐”,而是“强制停靠点”。如果 section 高度不固定、被 flex 或 grid 拉伸、或依赖内容自适应,浏览器无法确定停在哪,就会跳过 snap 或错位停靠。
移动端必须处理 overscroll-behavior 和 touch-action
iOS Safari 默认开启弹性回弹(overscroll),滚动到底部时会拉出空白再回弹,不仅破坏沉浸感,还会让 window.scrollY 在回弹阶段返回异常值,干扰 JS 判断逻辑。
隐藏滚动条要分浏览器写死
Chrome/Edge/Safari 下,scroll-snap 容器的滚动条默认可见,且会占位——即使设了 display: none,仍可能造成内容轻微偏移。
真正难的不是写几行 CSS,而是理解“滚动容器是否真正可滚动”和“子项是否具备明确停靠锚点”这两个前提——漏掉任一,scroll-snap 就会静默失效,连 console 都不报错。











