preload="metadata"是唯一正确写法,仅请求moov box元数据;失效主因是服务端缺Accept-Ranges头、视频未用faststart重写、或video元素动态插入;iOS Safari强制忽略preload,需结合link preload与load()调用。

preload="metadata" 是唯一正解
直接写 preload="metadata",不是 preload="true"、preload="1" 或空字符串——这些都会被浏览器当作 none 处理。它只请求 moov box(MP4 的元数据块),体积通常几 KB,不下载任何视频帧或音频帧。
metadata 模式失效的三个常见原因
写了 preload="metadata" 却发现浏览器在拉整个文件?大概率是以下某一项没到位:
- 服务端没返回
Accept-Ranges: bytes响应头——没有它,浏览器无法发起字节范围请求,只能硬下前几 MB 甚至全量才能读到时长 - 视频文件没用
ffmpeg -c copy -movflags +faststart重写——moov 在文件末尾时,metadata 模式退化为全量下载 -
<video></video>是 JS 动态插入 DOM 的——preload 只对初始 HTML 解析阶段存在的元素生效,动态添加的不会触发预加载
为什么不能依赖 video.duration 判断是否加载完成
即使 preload="metadata" 生效,video.duration 初始仍是 NaN。元数据加载是异步过程,必须监听事件:
✅ 正确做法:video.addEventListener('loadedmetadata', () => { console.log(video.duration); });
❌ 错误写法:if (video.duration > 0) { ... } —— readyState 为 0(HAVE_NOTHING)时 duration 就是 NaN,iOS 上尤其稳定保持这个状态直到用户点击
移动端特别是 iOS Safari 的硬限制
iOS Safari 从 10 开始就无视所有 preload 值,静默降级为 none。你写 preload="metadata" 它也当没看见,更别说 auto。这不是 bug,是苹果强制策略。真正能起作用的是组合动作:
立即学习“前端免费学习笔记(深入)”;
- 用
<link rel="preload" as="video" href="xxx.mp4">主动发起请求(仅同域有效) - 配合
IntersectionObserver,等视频即将进入视口时再调用video.load() - 确保
poster属性已设,避免白屏——因为 iOS 根本不会提前拉元数据,封面图是你唯一的视觉缓冲
最常被忽略的不是怎么写 preload,而是服务端配置和视频文件结构——这两项没搞定,HTML 里写得再标准也没用。



















