poster是视频元数据未就绪时的静态占位图,不响应点击、不控首帧、无无障碍语义;常见失效因浏览器优先渲染首帧、兼容限制或ios safari忽略策略。

poster 属性不是“封面图”,是浏览器在视频元数据未就绪、未播放、或加载失败时显示的静态占位图——它不响应点击,不控制首帧,也不参与无障碍语义。设了却看不见?大概率不是写法错,而是浏览器压根没让它出场。
为什么poster经常一闪就消失
Chrome、Edge 等浏览器一旦解码出视频第一帧(哪怕只是黑场或 logo 动画),立刻用该帧覆盖 poster,不管用户点没点播放。这不是 bug,是渲染优化逻辑。
- 设置了
autoplay且资源已缓存 → 封面几乎不可见 - 视频本身含内嵌缩略图(如某些 FFmpeg 编码输出)→ 浏览器优先取内嵌图
- 没加
preload="metadata"→ 元数据加载慢,但部分浏览器仍会跳过poster直接尝试解码 - iOS Safari 15–16 对 >200KB 的
poster图片懒加载,不加preload就不发请求
poster 路径和格式怎么写才稳
相对路径容易因 HTML 所在位置变化而 404;base64 在旧版 Android WebView 中直接被忽略;WebP 在老 iOS 上不渲染——这些都不是配置问题,是硬性兼容限制。
- 用绝对路径最可靠:
poster="/assets/cover.jpg"(以/开头) - 只用
.jpg或.png,避免.webp和.svg - 尺寸建议与视频宽高比一致(如 16:9 视频配 1280×720 图),否则拉伸失真
- 别写
poster="data:image/png;base64,...",部分环境静默失败
移动端点击封面播放不了?不是poster的问题
iOS Safari 和多数安卓 WebView 明确禁止在无用户手势上下文中触发 video.play()。poster 本身无法绑定事件,点它不会触发任何回调。
- 不要给
<video poster="..."></video>直接写onclick="this.play()" - 用包裹层实现:
<div class="video-overlay"><img src="cover.jpg"></div>,监听该<div> 的点击,再调 <code>video.play() - 每次换封面后记得调
URL.revokeObjectURL(),否则内存泄漏 - 真机测试必须做,Chrome DevTools 的 touch 模拟和真实 iOS 行为差异极大
- 轻量方案:用 FFmpeg 导出首帧,确保和
poster图像内容、宽高比、黑边完全一致:ffmpeg -i input.mp4 -ss 00:00:00.000 -vframes 1 -q:v 2 cover.jpg - 强控方案:用
preload="metadata"+loadedmetadata事件,把poster图作为background-image设置到<video></video>上,等play事件再清空 —— 这样封面不受视频加载节奏影响 - 动态上传封面时,别改
video.poster,改<img>层显隐,否则很多浏览器不重绘
真正可控的“首帧封面”只有两种务实做法
依赖 poster 实现“始终可见 + 可点击 + 内容精准匹配首帧”,在当前浏览器生态里不存在银弹。要么提前对齐,要么绕开原生机制。
最常被忽略的一点:iOS Safari 某些版本会彻底忽略 poster,连 404 都不报。这时候保底策略不是修路径,而是用一层 <img> 盖上去,并严格同步 playing / pause 状态。











