ios safari 强制将 preload 设为 none,因未获用户手势前禁止音视频网络请求以节省蜂窝流量,即使设为 auto 或 metadata 也静默失效,且不报错;验证需通过网络面板无请求及事件监听确认。

不是被“忽略”,而是被强制覆盖为 none —— iOS Safari 从不执行你写的 preload="auto" 或 preload="metadata",它自己说了算。
为什么 iOS Safari 总是走 none 路线
iOS Safari 在用户首次交互(比如 touchstart、click)前,根本不会触发任何音视频资源的网络请求,这是 Apple 的硬性策略,目的是防止后台偷偷消耗蜂窝流量。哪怕你写的是 preload="auto",Safari 也会静默把它当 none 处理,连 loadstart 事件都不会发。
- 所有 iOS/iPadOS 版本均适用,包括最新版(截至 2026 年 4 月)
- 这个行为不报错、不警告,也查不到被“覆盖”的痕迹,只能靠实测验证
- 即使你用
video.load()主动调用,在无用户手势上下文时仍会失败(抛出NotAllowedError)
preload="none" 在 iOS 上的实际效果
它不是“更保守”,而是“最符合预期”——因为其他值本来就不生效,设成 none 反而让行为可预测:
- DOM 渲染快,不会阻塞页面解析或触发隐藏请求
- 配合
controls或自定义播放按钮,点击后手动调用load()+play()是唯一可靠路径 - 避免在列表页中大量
<video></video>标签造成内存/连接数飙升(Android Chrome 对auto就没这么克制)
怎么验证 preload 是否真被绕过
别信文档,看网络面板和事件流:
- 打开 Safari 开发者工具(需 macOS + 连接 iOS 设备),切到 Network 面板,刷新页面 —— 没有媒体请求发出,就说明
preload生效了(即:被强制设为none) - 监听
video元素的loadstart、loadedmetadata,iOS 下这些事件在用户交互前基本不会触发 - 在
touchstart回调里立刻console.log(video.networkState),大概率是0(NETWORK_EMPTY),证明尚未加载
跨平台兼容写法建议
不要为 iOS 单独 hack,用统一逻辑适配所有环境:
- HTML 中统一写
preload="none",去掉侥幸心理 - 播放按钮绑定
click或touchend(注意防重复触发),并在回调内调用video.load()→ 等待loadedmetadata→ 再video.play() - 如果要用
loop,确保元数据已加载完成再设,否则 iOS 下可能失效(loop属性在loadedmetadata前设会被忽略)
真正容易被忽略的点是:iOS 不只是禁 preload,它把整个媒体加载生命周期都绑在用户手势上,连 canplaythrough 这类事件都不可靠;想稳定控制,就得接受“一切始于一次点击”这个前提。











