preload="auto"并非全量加载开关,Chrome限预加载1–5秒,iOS Safari静默降级为none,Android WebView仅metadata;真正全缓冲需video.load()配合progress事件或XHR+Blob手动加载。

preload="auto" 不能在后台全量加载视频——这不是配置问题,是浏览器行为限制。
它从来就不是“全加载开关”,名字带 auto 只是历史遗留误导。真实行为:Chrome 桌面最多预加载前 1–5 秒;iOS Safari 直接无视,静默降级为 none;Android WebView 和微信内核普遍只走 metadata 流程。写了 preload="auto" ≠ 视频文件被下载完,更不触发 canplaythrough。
真正想让视频在用户点击前就完成全缓冲,得绕开 preload,用主动控制手段:
-
video.load()必须在 DOM 就绪后显式调用(不能靠属性自动触发) - 配合监听
progress事件判断缓冲进度:Math.round(video.buffered.end(0)) / Math.round(video.seekable.end(0)) === 1 - 若需强制全量下载,可用
XMLHttpRequest+responseType = 'blob'主动拉取整个文件,再用URL.createObjectURL()赋给video.src -
<link rel="preload" as="video" href="xxx.mp4">可提前建立连接并缓存,但不触发解码,也不改变video元素自身状态
注意:动态插入的 <video></video> 元素,哪怕 JS 设置了 preload = "auto",也完全无效——preload 只在 HTML 解析阶段参与资源调度。
立即学习“前端免费学习笔记(深入)”;
preload="auto" 在 iOS Safari 上根本不起作用
从 iOS 10 开始,Safari 对所有 preload 值(包括 auto)一律静默降级为 none。这不是 bug,是苹果强制的流量与电池策略。即使你同时写了 autoplay 和 preload="auto",preload 也会被直接忽略。
video.readyState 在 iOS 上会长期卡在 0(HAVE_NOTHING),直到用户手势触发播放才开始加载。别试图用 UA 判断后设 auto——写了等于没写。
preload="metadata" 是唯一能稳定生效的选项
它只请求 MP4 文件头部的 moov box(通常几 KB),用来获取时长、宽高、封面帧等元数据。但有两个硬依赖:
- 服务端必须返回
Accept-Ranges: bytes响应头,否则浏览器无法发起字节范围请求,可能退化为下载前几 KB 甚至整文件 - 视频文件必须经
ffmpeg -c copy -movflags +faststart重写,确保moov在文件开头;否则浏览器得下载全部才能解析元信息
配合 poster 属性,能立刻显示占位图,避免白屏闪烁。监听 loadedmetadata 事件确认元信息就绪——别依赖 preload 属性值或 readyState。
动态加载视频时,preload 属性形同虚设
懒加载组件、Vue/React 动态渲染的 <video></video>,哪怕模板里写了 preload="auto",也不会触发任何预加载行为。因为浏览器只在初始 HTML 解析阶段读取该属性。
真正起作用的是:
- 用
IntersectionObserver监听视频即将进入视口 - 触发时调用
video.load() - 再监听
canplay或loadeddata后展示控件或自动播放
如果视频是列表页中多个 item 的一部分,千万别给每个都设 preload="auto"——大文件(>100MB)下极易耗尽带宽,拖慢其他资源。
最常被忽略的一点:全量缓冲 ≠ 用户体验更好。现代浏览器按需加载是合理策略,强行全载反而增加首屏延迟、浪费流量、触发 iOS 后台限流。真要后台全加载,得自己用 Blob + XHR 控制,但代价是内存占用和首次交互延迟。



















