HTML5字幕必须严格满足四要素:WebVTT文件首行为顶格全大写WEBVTT、UTF-8无BOM编码、时间戳格式为HH:MM:SS.mmm --> HH:MM:SS.mmm;<track>须为<video>直接子元素且位于所有<source>之后;必需kind、srclang、label、src四属性且值合法;服务端须返回text/vtt MIME类型。

track标签必须嵌在video内部,且位置严格限定
浏览器只认<video>内部、所有<source>闭合之后、</video>之前的<track>。放错位置——比如写在<source>前面、套在<div>里、或丢到<video>外面——字幕完全不加载,控制台也不会报错,纯静默失效。
常见错误写法:
<video> <track kind="subtitles" src="zh.vtt" srclang="zh" label="中文"> <source src="movie.mp4" type="video/mp4"> </video>这种顺序下 Chrome、Firefox、Safari 全部忽略该轨道。
- 正确结构必须是:
<video>→<source>→<track>→<track>→</video> - 多个
<track>可并列,顺序不影响菜单显示,但影响default的生效优先级(第一个带default的被启用) - 不能用 JS 动态插入
<track>后指望原生字幕菜单自动识别——浏览器只解析初始 HTML 中的嵌套结构
四个属性缺一不可:kind、srclang、label、src
kind="subtitles"不是可选装饰项,拼错(如"subtitle")、留空、或写成"captions"却没配听障场景,都会导致整条轨道被浏览器静默丢弃。同样,srclang必须是标准 BCP 47 标签(如"zh"、"en-US"),写"chinese"或"CN"无效;label为空时,菜单里只显示“字幕”或“(no label)”,用户无法区分中/英/日。
-
kind只能是"subtitles"、"captions"、"descriptions"等合法值,"chapters"和"metadata"不会出现在字幕菜单里 -
src路径必须可访问:本地file://协议下所有<track>加载均被禁用,必须起本地服务(如python3 -m http.server) - 跨域时,服务端需返回
Access-Control-Allow-Origin头,否则控制台报No 'Access-Control-Allow-Origin' header
VTT 文件本身极易出错,格式比内容更关键
哪怕时间轴对得再准,只要文件开头不是顶格WEBVTT、带 BOM、时间戳用逗号分隔毫秒(00:01:23,456)、或块之间少一个空行,整个字幕就彻底不显示。浏览器不报语法错误,只静默失败。
- 首行必须是全大写
WEBVTT,前后无空格、无 BOM、无注释 - 时间戳格式强制为
00:01:23.456 --> 00:01:26.789(毫秒三位,句点分隔) - 每段字幕块之间必须空一行;序号行可有可无,但若有,必须单独成行
- 服务器必须返回
Content-Type: text/vtt,Nginx/Apache 需显式配置 MIME 类型,否则 Safari 可能拒绝解析
移动端 Safari 的 default 不生效,JS 控制要等 readyState
iOS/iPadOS Safari 会加载<track>并暴露进video.textTracks,但写了default也不会自动启用——track.mode默认是"disabled",原生字幕按钮甚至默认隐藏。必须用 JS 手动拉取轨道并设mode = "showing",但直接赋值大概率失败,因为 VTT 还没加载完。
立即学习“前端免费学习笔记(深入)”;
- 动态控制前,必须确认
track.readyState === 2(LOADED),或监听track.onload事件 - 不要轮询
readyState,而是绑定video.textTracks.onaddtrack捕获新轨道加入 - 真机测试务必连 Safari DevTools 查看
video.textTracks.length和每个track.srclang是否真实存在,别只信桌面 Chrome
text/vtt MIME 类型没配、或文件存成了 UTF-8 with BOM,字幕就永远黑屏——这两点没法靠浏览器开发者工具一眼看出,得查网络请求响应头和用十六进制编辑器验 BOM。



















