scroll-snap-type 写在 body 或 html 上失效,因页面滚动由 html 处理且通常无溢出;须新建显式可滚动容器并满足高度、overflow-y 和 scroll-snap-type 三条件,同时规范 section 高度与对齐方式,并处理 ios 回弹及滚动条隐藏。

scroll-snap-type 为什么写在 body 上没反应
直接给 body 或 html 加 scroll-snap-type: y mandatory 几乎必然失效。原因很实在:浏览器默认把页面滚动交给 html 元素处理,但它通常没有溢出内容(overflow-y 不触发),导致 snap 根本不计算。
必须新建一个显式可滚动容器,比如 <div class="scroll-container">,并同时满足三个硬性条件:
<ul>
<li>
<code>height: 100vh 或更稳妥的 min-height: 100dvh(适配 iOS/Android 地址栏收放)
overflow-y: scroll(hidden 不行,auto 在部分 Android WebView 中兼容差)scroll-snap-type: y mandatory别忘了重置根样式:html, body { margin: 0; padding: 0; height: 100%; },否则外边距会干扰容器尺寸计算。
每个海报 section 必须设 height 和 scroll-snap-align
只写 scroll-snap-align: start 不够。浏览器需要知道“停在哪”,如果 section 高度被 flex: 1、height: 100% 或内容撑开,Safari 和 Firefox 就可能忽略吸附,或停在错误位置。
必须显式设置:
-
height: 100vh(兼容性最广)或min-height: 100dvh(推荐新项目) -
scroll-snap-align: start(center在全屏场景下 Safari 支持不稳定) - 禁用
margin-top/margin-bottom——它会改变offsetTop,让视觉停靠点偏移
文字垂直居中别用 padding-top 模拟,改用 display: flex; align-items: center;,避免干扰 snap 基准线。
iOS Safari 的 mandatory 不是真强制
快速滑动后松手,iOS Safari 可能停在两个吸附点之间——这不是 bug,是 WebKit 对滚动惯性的主动妥协。尤其当 section 高度不一致时更明显。
要提升停靠精度:
- 确保所有
section高度严格一致(如都用height: 100vh,不用min-height) - 避免在
position: sticky或含transform的父容器里嵌套scroll-snap - 真机测试必不可少;模拟器常表现过度理想
- 必要时监听
scrollend事件做 JS 修正(注意旧版 Safari 不支持)
实际滚动是否吸附,不看 DevTools 样式面板,而要看松手后是否真的停在区块边界——那才是唯一可信的判断依据。
移动端必须加 overscroll-behavior-y: contain
iOS Safari 默认开启弹性回弹(overscroll),滚动到底部时会拉出空白再回弹,不仅破坏沉浸感,还会让 window.scrollY 在回弹阶段返回异常值,干扰 JS 判断逻辑。
在滚动容器上加 overscroll-behavior-y: contain,彻底禁用纵向回弹。横向滚动(如相册)必须加 touch-action: pan-x,否则 iOS 会默认锁死横向滑动。
隐藏滚动条要分浏览器写死:
- Chrome/Edge/Safari:
::-webkit-scrollbar { display: none; }+overflow-y: -webkit-scrollable-area(防占位偏移) - Firefox:
scrollbar-width: none(仅 Firefox 64+)
滚动条隐藏后,用户仍可通过空格键、方向键、触控板滚动,功能不受影响——但视觉干扰没了。











