原生标签播放mp4/h.264虽基础兼容,但存在ios强制全屏、android禁自动播放、桌面端泄露源地址等规范行为;需用户手势触发play()、preload="metadata"更稳妥、controls=false配合自定义ui;mp4非万能,h.265/av1支持有限,建议双轨输出h.264+vp9;autoplay需muted才可靠生效;seek卡住多因服务器未支持http range或moov box位置不当。

用 <video></video> 标签就能播,但默认控件不跨平台
浏览器原生 <video></video> 支持足够播 MP4/H.264,但 iOS Safari 会强制全屏、Android Chrome 可能禁自动播放、桌面端右键菜单暴露源地址——这些不是 bug,是规范行为。
常见错误现象:加了 controls 属性后,在 iPhone 上点播放直接跳全屏;设 autoplay 却没反应,控制台报 DOMException: play() failed because the user didn't interact with the document first。
- 必须等用户手势(如 click/touchstart)触发
play(),不能 onload 就调 -
preload="metadata"比"auto"更稳妥,避免移动端预加载整段视频 - 如果要自定义 UI,得关掉原生控件:
controls=false,再自己用<button></button>和currentTime等 API 控制
MP4 不是万能格式,H.265/AV1 在部分浏览器直接不识别
你导出的“MP4”可能是 H.265 编码,Chrome 110+ 支持,但 Safari 16.4 之前不支持;Firefox 目前仍不支持 H.265。AV1 更小更清,但只有 Chrome/Firefox/Edge 较新版本支持,iOS 完全不认。
- 生产环境建议双轨输出:
<source src="video.mp4" type="video/mp4"></source>(H.264+AAC) +<source src="video.webm" type="video/webm"></source>(VP9+Opus) - 用
ffmpeg -i in.mov -c:v libx264 -crf 23 -c:a aac -b:a 128k out.mp4保证兼容性 - 别依赖
canPlayType()返回"probably"——它在 Safari 上常误报,实际播放时才知是否真支持
自动播放被拦截?静音是唯一可靠绕过方式
Chrome/Firefox/Safari 都把有声音的自动播放视为骚扰,默认禁止。但加 muted 属性后,autoplay 就能生效,且不会弹权限提示。
MuiPlayer视频播放器插件是一款HTML5 视频播放插件,其默认配置了精美可操作的的播放控件,涉及了常用的播放场景,例如全屏播放、播放快进、循环播放、音量调节、视频解码等功能。
- 写法必须是:
<video autoplay muted loop></video>,muted要显式存在,不能靠 JS 后设(有些浏览器不认) - 如果业务需要带声播放,只能等用户点击一次页面任意位置后再调
video.play(),且不能加setTimeout延迟,否则失去“用户激活”上下文 - 移动端尤其注意:touchend 比 click 更可靠,click 在 iOS 上有 300ms 延迟,可能错过激活窗口
seek 到未缓冲位置卡住?不是代码错,是网络或编码问题
用户拖进度条到后面,视频停住、转圈、network 面板显示 pending,大概率是服务器没配 HTTP Range 请求支持,或视频没做关键帧对齐。
立即学习“前端免费学习笔记(深入)”;
- 检查响应头是否有
Accept-Ranges: bytes,Nginx 默认开启,但某些 CDN 或静态托管(如 GitHub Pages)不支持断点续传 - 用
ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1 video.mp4确认时长可读;若返回空,说明 moov box 在文件末尾,需用ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4修复 -
video.buffered是只读属性,不能靠它判断“能否拖”,要用loadedmetadata+seeking事件组合监听真实状态
真正麻烦的从来不是怎么写 <video></video>,而是你不知道视频文件本身有没有埋坑、CDN 是否透传了 Range 头、用户点的那一刻页面有没有被其他脚本阻塞了事件循环。










