正确做法是用scroll-snap-align+scroll-snap-type实现全屏滚动:容器需满足height:100vh、overflow-y:scroll/auto、为普通块级元素;子项必须设height:100vh和scroll-snap-align:start;移动端须加touch-action:pan-y并禁用-webkit-overflow-scrolling。

用 scroll-snap-align + scroll-snap-type 实现全屏滚动,不是靠 grid-template-rows: repeat(n, 100vh) —— 后者会撑高容器、错位、无法吸附,纯属误导。
scroll-snap-type 没生效?先检查容器是否满足三个硬条件
浏览器根本不识别滚动容器,不是属性写错了,而是它压根没被当作“可吸附目标”:
-
height: 100vh(必须是height,min-height或内容撑高都不行) -
overflow-y: scroll或auto(hidden禁滚动,visible不创建滚动上下文) - 必须是普通块级元素,比如
<div class="scroller">;在 <code>body或html上设等于白写子项必须显式设
scroll-snap-align: startscroll-snap-type只是开关闭,真正决定停在哪的是每个子项的scroll-snap-align。只设容器不设子项,滚动照样滑过不停:- 垂直全屏停驻顶部:用
scroll-snap-align: start - 想居中停驻:用
scroll-snap-align: center,但要求该子项height严格为100vh,否则锚点偏移 - 别用
margin-bottom分隔页面——它会让滚动距离 ≠ 视口高度,吸附点漂移;改用min-height: 100vh+box-sizing: border-box - 若子项内容超长导致自身高度 >
100vh,scroll-snap-align: start仍只锚定顶部,用户看到半截内容,此时应加overflow: hidden或限制内部高度
移动端 iOS Safari 必须补三处适配
缺任何一项,
scroll-snap都可能卡不住、跳帧或直接失效:立即学习“前端免费学习笔记(深入)”;
- 滚动容器加
touch-action: pan-y(横向轮播则用pan-x),否则系统可能拦截 touch 事件,绕过 snap 逻辑 - 删掉
-webkit-overflow-scrolling: touch(iOS 现代版本已弃用,留着反而冲突) - 每个子项必须是
height: 100vh(不能靠flex撑高,也不能有transform或will-change干扰布局层) - 刘海屏/全面屏需加
scroll-padding-top: env(safe-area-inset-top),否则第一屏顶部被遮挡
Grid 容器别写
grid-template-rows,改用grid-auto-flow: row全屏滚动的本质是“每个区块占据一个视口高度并 snap 到位”,不是靠 Grid 行高堆出来:
- Grid 容器设
display: grid+grid-auto-flow: row,不写grid-template-rows - 每个直接子元素(如
<section></section>)设height: 100vh+scroll-snap-align: start - 必须清除
body { margin: 0 },否则首屏顶部多出默认 8px 空白 - 如果坚持用 Grid 控制视觉分屏,
1fr是唯一安全替代方案:容器设height: 100vh,再写grid-template-rows: repeat(n, 1fr),此时每行均分可用空间(自动扣除gap)
最易忽略的是:滚动容器必须是独立
<div>,不能和 <code>body混用;100vh在 iOS Safari 中地址栏收放会变,但scroll-snap不重算——这意味着你得靠scroll-padding-top和env()补偿,而不是指望它自适应。 - 垂直全屏停驻顶部:用


















