video和audio标签必须配<source>多格式兜底,不能仅用src属性,否则Safari(尤其iOS)静默跳过、Chrome可能报解码失败;<source>的type须与服务器Content-Type严格匹配,顺序决定fallback路径,iOS不支持webm/ogg,字幕需用<track>显式声明并设default。

video 和 audio 标签必须配 <source>,不能只写 src
只在 <video> 上直接写 src="xxx.mp4",Safari(尤其是 iOS)会静默跳过,Network 面板里根本看不到请求;Chrome 可能加载但报 ERR_CONTENT_DECODING_FAILED。浏览器需要靠 type 属性提前过滤格式,而不是瞎试。
-
<source>的type必须精确匹配 MIME 类型:比如type="video/mp4"对应服务器返回Content-Type: video/mp4,返回application/octet-stream就失败 - 顺序影响 fallback:把
webm放最前(适配 Chrome/Firefox),mp4放最后(兜底 Safari/Edge) - iOS 完全不支持
webm(含 VP8/VP9/AV1)和ogg,写了也白写——连请求都不会发
字幕必须用 <track> 声明,且 srclang 和 default 不可省略
仅放一个 VTT 文件链接不算合规。屏幕阅读器不会主动读字幕内容,必须通过 <track> 显式挂载,否则 WCAG 2.1 第1.2.2条(字幕必需)直接不达标。
-
kind="subtitles"是基础,但还要配srclang="zh"和label="中文",否则多语言切换时无法识别 - 至少一条字幕轨必须带
default属性,否则首次播放无字幕——用户不会手动点开“字幕”按钮 - 别把字幕文件放在子目录却漏写路径:
src="captions/cn.vtt"要确保服务器真能返回text/vttMIME 类型
播放控件必须支持键盘操作,禁用 controls 时更要手动补 aria- 属性
自定义播放按钮(比如用 <button> 实现)若没加 role="button"、aria-pressed 和 aria-label,键盘用户 Tab 到它就卡住,屏幕阅读器完全不知道这是干啥的。
- 播放/暂停状态必须实时同步:
aria-pressed="true"表示暂停中,false表示播放中 -
aria-label要带上下文,比如"暂停:当前进度 42 秒",不能只写"暂停" - 进度条需有
aria-valuemin、aria-valuemax、aria-valuenow,且绑定oninput更新值
移动端自动播放策略下,muted 是硬性前提
iOS 和 Android Chrome 都强制要求视频自动播放必须静音,否则直接拦截。哪怕你写了 autoplay,没 muted 就等于没写。
立即学习“前端免费学习笔记(深入)”;
-
autoplay+muted才可能触发自动播放;加playsinline确保 iOS 在页面内播放(不进全屏) - 如果业务必须带声自动播(比如教育类 App 的引导语音),得先让用户手势触发一次播放,之后才能解除静音限制
- 别依赖
play()的 Promise 返回值判断是否成功:iOS 上静音未设就调play(),Promise 会 reject,但错误信息是空对象,没提示
Content-Type 响应头——这两处出错,所有前端努力都归零。



















