video 的 poster 属性仅静态声明,不可控;需用 css 背景 + js 事件(如 loadedmetadata)叠加可编程封面层实现稳定显示,避免路径错误、类型不符、ios 懒加载及 chrome 隐藏等问题。

video 元素的 poster 属性不能“控制”,只能声明——它只在视频未加载元数据前静态显示,且浏览器有权随时覆盖或跳过;真要可控,得用 CSS 背景 + JS 事件兜底。
为什么写了 poster 却看不到图?
不是代码写错,而是浏览器根本没请求那张图,或请求失败后静默空白:
- 图片路径以 HTML 文件为基准解析,
poster="cover.jpg"在/pages/video.html下会请求/pages/cover.jpg,不是根目录 - 服务器返回 404、403 或 Content-Type 不是
image/jpeg等合法类型,浏览器不报错,只留空 - iOS Safari(15–16)对 >200KB 的 poster 懒加载,若没配
preload="metadata",压根不发请求 - Chrome v78+ 在
loadedmetadata触发后立即隐藏poster,哪怕用户还没点播放
怎么让 poster 真正稳定显示到用户点击?
原生 poster 不支持显隐控制,必须叠加一层可编程的封面层:
- 给
<video></video>外包一个<div class="video-wrapper">,里面放一个 <code><img class="poster-fallback"> - 监听
loadedmetadata事件(不是canplay),此时元数据已就绪但首帧未必渲染,是插入封面层的最佳时机 - 用
video.poster的值赋给img.src,再设img.style.display = 'block' - 监听
play或timeupdate(首次非零时间),立刻img.style.display = 'none' - 别忘了:每次调用
URL.createObjectURL()后,必须配对URL.revokeObjectURL() -
video.style.backgroundImage = 'url(' + video.poster + ')'可在loadedmetadata后设置,兼容性比动态改poster高得多 - 必须加
background-size: cover和background-position: center,否则拉伸变形 - 播放开始后,需手动清掉:
video.style.backgroundImage = '',否则遮挡控件或首帧 - 如果视频支持
playsinline(尤其 iOS),记得同时加webkit-playsinline,否则 poster 层可能错位 - 真正能刷新封面的只有重载流程:
video.src = ''→video.poster = newUrl→video.src = oldSrc→video.load() - 这个过程会中断播放、清空缓冲、触发完整加载,不适合频繁切换
- 更轻量的做法:上传新封面时,只更新
<img class="poster-fallback">的src,并控制其显隐 - 移动端注意:iOS Safari 对
object-fit支持不一致,cover在某些版本中失效,优先用 background-image 方案
poster 和 background-image 哪个更可靠?
直接用 CSS background-image 更可控,但要注意覆盖时机和内存:
动态换封面时最容易踩的坑
别碰 video.poster = newUrl——90% 浏览器忽略它,包括 Safari:
真正难的不是写对 poster,而是在 autoplay、preload、CORS、首帧解码、iOS 手势策略之间,找到那个所有浏览器都认的交集点——它往往不在 HTML 属性里,而在你监听的事件和叠的那层 DOM 中。











