preload="auto" 在 ios safari 等浏览器中实际无效,等同于未设置;真正生效的只有 preload="metadata"(需服务端支持 accept-ranges 和 faststart)或 js 调用 load()。

preload="auto" 对 video 根本不生效,别白写了
HTML <video></video> 的 preload 属性设为 "auto" 在绝大多数移动端(尤其是 iOS Safari)和部分桌面浏览器中,实际等同于 "none" 或静默降级为 "metadata"。这不是 bug,而是浏览器主动策略:iOS 从 10 开始就无视所有 preload 值,哪怕你写了 preload="auto" 也等于没写。
常见错误现象:
- DevTools Network 面板里看不到视频请求,
video.readyState长期卡在0(HAVE_NOTHING) - 页面加载完、甚至用户滚动到视口内,视频仍无任何网络请求
- 动态设置
video.preload = "auto"后调用load()才触发下载——说明属性本身没起作用
真正起效的只有两个时机:
- 静态 HTML 中声明的
<video preload="metadata"></video>(仅元数据) - JS 显式调用
video.load()(触发完整加载)
link rel="preload" as="video" 效果极不稳定,慎用
<link rel="preload" href="xxx.mp4" as="video"> 理论上能提前发起请求,但实际兼容性差、行为不可控:
- Chrome 支持但优先级常被降为
Low,不如as="fetch"可靠 - Safari 完全忽略
as="video",既不提升优先级也不进缓存池 - 即使请求发出去,
<video></video>元素不会自动复用该响应——它仍会发自己的请求,造成重复下载 - 服务端若未返回
Accept-Ranges: bytes,预加载可能直接下载整个文件(尤其未faststart的 MP4)
更现实的做法是:
- 对首屏核心视频,用
<link rel="preload" href="xxx.mp4" as="fetch" crossorigin>(绕过as限制) - 随后在
<video></video>上监听loadedmetadata,再手动赋值src并调用load() - 避免在
里写多个视频 preload——带宽竞争明显,首屏图/字体可能被挤掉
metadata 模式必须满足两个硬条件,否则退化成全量下载
preload="metadata" 看似省流量,但失效后反而更糟:浏览器可能下载前几 KB 甚至整个文件来“猜”元数据。关键依赖两点:
- 服务端响应头必须含
Accept-Ranges: bytes—— 否则浏览器无法做字节范围请求,只能按顺序读取直到找到moovbox - 视频文件需经
ffmpeg -c copy -movflags +faststart重写 —— 把moovbox 移到文件开头,否则元数据在末尾,不下载完就解析不了
验证方式很简单:
- 用
curl -I your-video.mp4查看响应头是否有Accept-Ranges: bytes - 用
ffprobe -v quiet -show_entries format=duration your-video.mp4测试本地能否秒出时长(不能说明moov位置不对)
真要控制流量,得靠 IntersectionObserver + load() 主动调度
想实现“进入视口才加载视频”,别指望 preload 属性或 loading="lazy"(<video></video> 不支持该属性)。可靠路径只有一条:
- 初始
<video preload="none"></video>,不设src - 用
IntersectionObserver监听元素是否可见 - 可见后赋值
video.src,立即调用video.load() - 监听
canplay或loadeddata再显示控件或自动播放(iOS 需用户手势)
容易被忽略的细节:
- 动态插入的
<video></video>,即使模板里写了preload="metadata",也不会触发预加载——DOM 必须初始存在 - 调用
load()后,video.buffered和video.seekable才开始更新,别用readyState判断“是否已加载” - 如果视频来自跨域 CDN,
load()前得确保crossorigin属性已设,否则可能因 CORS 失败静默中断
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











