preload="metadata" 能立即获取时长、封面和宽高,仅请求 moov box(几 kb),但需服务端支持 accept-ranges: bytes 且视频经 faststart 优化,否则无法生效;它不适用于 hls/dash,且动态插入 video 需手动调用 load()。

preload="metadata" 能立刻拿到时长、封面和宽高
它只请求 MP4 文件开头的 moov box(通常几 KB),不下载任何音视频帧,但能准确读出 duration、videoWidth/videoHeight、封面帧(用于 poster 渲染)以及音轨数量。这些信息足够你初始化播放器控件、渲染进度条、显示时长标签——用户点击播放前界面就已“准备就绪”。
常见错误现象:设了 preload="metadata" 却拿不到 duration,或 video.readyState 长时间卡在 0;这往往不是 HTML 写错了,而是服务端没返回 Accept-Ranges: bytes 响应头,或者视频文件没用 ffmpeg -c copy -movflags +faststart 重写,导致 moov 在文件末尾,浏览器被迫下载大量数据才能解析。
比 preload="none" 快 100–300ms 首帧渲染
关键不在“是否加载”,而在“何时开始加载”。preload="metadata" 把元数据请求提前到 video 元素插入 DOM 后立即触发;而 preload="none" 下,必须等用户点击播放、调用 play(),才启动元数据请求 + 首帧解码两步操作。实测中,这个时间差在弱网、高延迟 DNS/SSL 场景下尤为明显。
但要注意:preload="metadata" 不等于“首帧已就绪”。它只是把解码依赖的元信息拉下来了,真正画面帧仍需后续请求。若页面有多个 video,全部设为 metadata 可能触发浏览器并发连接数限制(如 Chrome 默认 6 个),反而拖慢整体加载。
iOS Safari 和多数移动端浏览器最认它
preload="auto" 在 iOS Safari 上基本被无视,一律降级为 none;Android WebView、微信 X5 内核也普遍不执行 auto 行为。preload="metadata" 是目前兼容性最好、行为最可预期的取值——桌面 Chrome/Firefox/Safari、主流 Android 浏览器都稳定支持它,且不会因省电模式、后台标签页等策略被静默禁用。
不过动态插入的 video 元素(比如通过 JS 创建后 append 到 DOM),preload 属性常无效;必须配合 IntersectionObserver 或显式调用 load() 才能触发元数据请求。微信 X5 还有首次 load() 静默丢弃风险,建议加 setTimeout(() => video.load(), 0) 微调。
它不解决流媒体(HLS/DASH)的首帧问题
当 src 指向 .m3u8 或通过 MediaSource 动态赋值时,preload="metadata" 完全无效——浏览器根本不解析 m3u8,也不会发起任何分片请求。一切调度由 hls.js 或 MSE 控制层接管。
想优化 HLS 首帧,得在 JS 层预热:提前 fetch 第一个 m3u8,解析出首个 .ts URL,再用 fetch() 或 new Image().src 触发 DNS/TCP/TLS 缓存;注意跨域和 CORS 配置。否则,写了再多 preload="metadata" 也没用。
真正容易被忽略的是服务端配置:没有 Accept-Ranges: bytes,preload="metadata" 就可能变成流量黑洞;moov 不在开头,首帧延迟就不可控——这些不在 HTML 里写,但决定了 preload 写得再对也没用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











