poster仅在元数据加载前显示,loadedmetadata触发后即隐藏;Chrome/Edge首帧可渲染即移除,Safari保留至播放,Firefox缺type则跳过渲染;需CSS+JS接管实现可控展示。
poster 属性不是“加了就显示”,它只在视频元数据加载完成前起作用;一旦 loadedmetadata 事件触发,浏览器就会丢弃 poster、准备渲染首帧——哪怕视频还没播放,用户也看不到它了。
这不是 bug,而是 Chrome v78+ 之后的默认行为:poster 仅作为解码前的临时占位,loadedmetadata 一触发就隐藏。Safari 行为相反,会一直留到用户点击播放,导致跨浏览器体验割裂。
preload="metadata",可能压根不请求 poster 图<source></source> 缺少 type 属性,无法预判解码能力,直接跳过 poster 渲染阶段靠原生 poster 不行,得用 CSS + JS 协同接管:把 poster 当作视觉底图,而非依赖浏览器自动管理。
<video> 加内联样式:style="background: url(cover.jpg) center/cover no-repeat;",作为 fallback 底层loadedmetadata 后,动态插入一个绝对定位的 <img> 覆盖层,z-index 高于 video 控件play 或 timeupdate(首帧渲染后)再移除该 <img>,避免遮挡进度条::before 伪元素——多数浏览器不支持在 <video> 上生效直接改 videoEl.poster = 'new.jpg' 是无效的,浏览器不会重绘,尤其在 iOS Safari 中静默失败。
立即学习“前端免费学习笔记(深入)”;
videoEl.removeAttribute('poster'),再 setAttribute('poster', 'new.jpg')
videoEl.load() 强制刷新资源状态(注意:这会清空已缓冲的视频数据)URL.createObjectURL(blob) 动态生成 poster,记得在替换后调用 URL.revokeObjectURL() 防内存泄漏Access-Control-Allow-Origin: *),否则 iOS Safari 和部分 WebView 会静默拒绝即使所有参数都对,iOS Safari 某些版本仍会彻底忽略 poster——这不是配置问题,是实现差异。此时没有通用修复,只有两个务实选择:
poster,至少避免黑屏<div class="video-wrapper"><video></video><img class="poster-overlay" src="cover.jpg"></div>,初始 display: block,监听 playing 后 display: none
真正难的不是写对 poster 属性,而是在不同缓存状态、网络延迟、系统版本下,让它始终以可控方式出现——这意味着你要把它当作一个需要主动管理的状态,而不是一次性的 HTML 属性。