video必须用position: fixed而非100vw/100vh,因后者在ios地址栏显隐、滚动条出现时会导致跳动或留白;正确方案是fixed+top:0;left:0;width:100%;height:100%;object-fit:cover,并包裹于z-index:-1的div中,同时添加autoplay、muted、playsinline等属性确保兼容性。

video 必须用 position: fixed 而不是 100vw/100vh
用 width: 100vw; height: 100vh 会导致 iOS 地址栏显隐时视频跳动、桌面端滚动条占位后右侧留白,根本不可靠。真正能稳住全屏的只有 position: fixed; top: 0; left: 0; width: 100%; height: 100%,再配 object-fit: cover 防拉伸。
常见错误:video 直接放在 下,结果被其他 position: fixed 元素(比如导航栏)遮挡。正确做法是包一层 <div class="video-bg">,并设 <code>z-index: -1,确保它永远在最底层。
- 必须加
autoplay muted loop playsinline webkit-playsinline,缺一就会在 iOS 或 Chrome 里静音或强制全屏 -
preload="metadata"能减少黑屏闪动 - 至少提供 MP4 + WebM 双格式
<source></source>,否则 Firefox 会 fallback 到“不支持视频”提示
文字层必须用 position: relative + z-index 显式提升
很多人把文字塞进 video 的父容器里,再加 background-color: rgba(0,0,0,0.5),以为这样就能“压在视频上”——其实不行。video 是独立合成层,它的内容不会和父容器的背景色混合;文字若没脱离文档流,就根本不在 video 的“上方”,只是视觉错觉。
正确结构只能是三个同级节点:<video></video>、遮罩层(可选)、文字容器,三者都挂载在同一个父级下,且父级不能有 isolation: isolate。
- 文字容器必须设
position: relative(或absolute/fixed),否则z-index和混合模式都无效 - 推荐加
z-index: 10以上,避免被其他组件覆盖 - 如果要用
mix-blend-mode做文字透底效果,遮罩层不能是单色background-color,得用linear-gradient或带图片的多层背景
文字精准居顶需避免 margin-top 拉动整个块
直接给标题加 margin-top: 20px 看似简单,但会把整个文字容器往下推,导致和视频错位——尤其在响应式断点变化时更明显。这不是 bug,是块级元素流式布局的自然行为。
真正可控的方式是让文字和视频成为同一逻辑容器的子元素,用 Flex 或绝对定位锚定顶部位置。
- 方案一(推荐):文字容器设
position: absolute; top: 20px; left: 50%; transform: translateX(-50%),配合父容器position: relative - 方案二:用 Flex 布局,父容器
display: flex; flex-direction: column;,文字设align-self: center,再用margin-top控制间距(此时只影响自身,不牵连兄弟节点) - 别忘了加
pointer-events: none到 video 上,防止移动端误触暂停
移动端地址栏跳变和滚动穿透必须手动处理
iOS Safari 在滚动时会隐藏地址栏,触发视口高度重算,100vh 值突变,fixed 视频就会“抽搐”。这不是 CSS 能自动修复的问题,得靠 JS 微调。
简单但有效的补救:监听 scroll 和 resize,动态重设 video 高度为 window.innerHeight;同时给 body 加 overflow: hidden 防止页面滚动穿透到背后视频。
- 加
touch-action: none到 video 层,禁用双指缩放干扰 - 如果页面本身需要滚动,文字层建议用
position: sticky替代fixed,避免固定后脱离上下文 - 所有动画类操作(比如 fade-in)必须等
canplaythrough事件后再触发,否则首帧未加载就显示文字,体验割裂











