全屏纵向标签页切换必须用 scroll-snap-type + 固定高度 section 实现,禁用 hidden/display:none;需新建 scroll-container 包裹层,设 min-height: 100dvh、overflow-y: scroll、scroll-snap-type: y mandatory;section 用 height: 100vh 和 scroll-snap-align: start;依赖 document.fullscreenelement 判断状态,退出时调用 document.exitfullscreen()。

全屏页面里做纵向标签页切换,本质是「全屏 + 垂直滚动对齐」,不是传统 tabs 切换。直接用 hidden 或 display: none 会破坏全屏体验,也丧失滚动锚点能力。
为什么不能用普通 tabs 的 hidden/display 切换
全屏状态下,每个“标签页”应占据完整视口高度,并支持手指/滚轮自然滑动切换——这要求它们是连续的、可滚动的 DOM 序列,而不是靠 JS 显隐控制的离散区块。
-
hidden或display: none会让元素脱离文档流,scroll-snap-align失效,无法触发吸附 - 用户滑动时若靠 JS 监听位置再手动 show/hide,会卡顿、丢帧,且 iOS Safari 对
display切换有渲染延迟 - 退出全屏后,显隐状态容易错乱(比如上一页还 visible,但 scroll 已跳到别处)
必须用 scroll-snap-type + 固定高度 section
这是目前唯一能兼顾原生滚动性能、无障碍支持、以及 Safari/Chrome 兼容性的方案。关键不在“标签”,而在“可滚动容器 + 吸附锚点”。
- 新建包裹层
<div class="scroll-container">,不要直接设在 <code>body或html上 - 该容器需同时满足:
min-height: 100dvh、overflow-y: scroll、scroll-snap-type: y mandatory - 每个“标签页”用
<section></section>,并设height: 100vh(不用100%)和scroll-snap-align: start - 移除所有
margin-top/bottom,改用padding或flex居中,避免吸附偏移 - 进全屏前,确保目标容器已挂载:
el.offsetParent !== null,否则requestFullscreen()静默失败 - 监听
document.addEventListener('fullscreenchange', ...),检查document.fullscreenElement === containerEl - 滚动后判断当前屏:用
containerEl.children[index].getBoundingClientRect().top 辅助定位,但最终以 <code>scroll-snap-align触发的视觉停靠为准 - 退出全屏必须调
document.exitFullscreen().catch(() => {}),否则document.fullscreenElement不清空,UI 状态脱节 - 禁用
transform、will-change、filter等可能干扰布局计算的样式 - 父容器别用
display: flex包裹.scroll-container,它会隐式拉伸子项,破坏100vh计算 - 降级 fallback:监听
scrollend(Chrome/Firefox 支持),或用setTimeout(() => { ... }, 100)捕获滚动结束,再手动scrollTo({ top: targetY, behavior: 'smooth' }) - 别依赖
scroll-behavior: smooth做核心逻辑——iOS Safari 中它常被忽略,只当装饰用
document.fullscreenElement 是唯一状态依据
用户点击按钮进全屏后,你得知道当前在哪一屏——但别读 scrollTop 或自己记 index,那不可靠。正确做法是结合全屏状态与滚动位置。
iOS Safari mandatory 容易失效?降级策略要写死
Safari 对 scroll-snap-type: y mandatory 要求极严,稍有偏差就退化为 proximity,导致滑一半停不住。这不是 bug,是设计限制。
真正难的不是写出能动的代码,而是让每种设备都停得准、切得稳、退得干净。Safari 的 mandatory 规则、移动端 touch 事件的 passive 默认值、全屏后 viewport 变化带来的 dvh/hvh 差异……这些细节不逐个踩过,线上就容易白屏或错位。











