track元素必须作为video直接子元素且位于source之后、video闭合前,kind、srclang、label、src四属性缺一不可,WebVTT文件首行须为“WEBVTT”加空行、UTF-8无BOM、Content-Type为text/vtt。

track元素必须作为video的直接子元素且位置严格固定
浏览器只在<video></video>开始标签之后、所有<source></source>闭合之后、之前这个狭窄区间内解析<track></track>。放错位置等于没写,而且几乎不报错——video.textTracks.length恒为0,控制台也安静得可怕。
常见失效位置包括:
-
<track></track>写在<source></source>前面 → 被忽略 -
<track></track>包在<div>里或放在<code>外 → 不发起网络请求 - 多个
<track></track>之间插了HTML注释或空行 → Safari 可能中断后续解析 - 用JS动态
appendChild插入到已加载完成的<video></video>中 → 静默失败(DOM已冻结扫描) -
kind="subtitles":必须全小写、拼写完整;kind="caption"、kind="subtitles "(末尾空格)均无效 -
srclang:必须是合法 BCP 47 码,如"zh-Hans"、"en-US"、"ja";"chinese"、"zh_CN"、空值全部被忽略 -
label:用户实际看到的菜单名,建议含变体说明,如label="中文(简体)";为空时可能显示(no label),多语言场景下无法区分 -
src:路径需可访问;若跨域,服务端必须返回Access-Control-Allow-Origin: *,否则 Firefox/Edge 静默失败 - 首行必须是全大写
WEBVTT,后面跟一个空行(不能有BOM,不能是webvtt或WEBVTT) - 时间戳格式必须为
hh:mm:ss.mmm --> hh:mm:ss.mmm,毫秒必须三位(01:23:45.670✅,01:23:45.67❌) - 每段字幕块必须包含编号、时间戳、文本三部分,缺一不可
- 文件编码必须为UTF-8,无BOM
- 服务端必须返回
Content-Type: text/vtt,否则部分浏览器拒绝加载 - 仅允许在一个
<track></track>上设置,多个会导致行为未定义(多数浏览器只启用第一个) - 设了
default不代表自动显示——它只表示“用户没手动选时的 fallback”,仍需用户在右键菜单中启用字幕功能 - 可通过 JS 检查:
video.textTracks[0].mode === 'showing',但不能靠default属性值来判断当前是否显示
kind、srclang、label、src 四个属性一个都不能少
浏览器不做任何容错推断。漏掉任意一个,该轨道就不会出现在右键字幕菜单里,不是“不显示”,而是菜单里压根没有选项。
关键细节:
立即学习“前端免费学习笔记(深入)”;
WebVTT文件格式容错率近乎为零
<track></track>本身不渲染内容,它只是声明外部轨道;真正决定成败的是.vtt文件。哪怕只错一个字符,Chrome/Firefox 就静默丢弃整条轨道——Network 面板看不到失败请求,控制台不报错,字幕菜单就是空的。
合规要点:
移动端和默认行为要额外注意
移动端 Safari 要求<video></video>带controls属性,否则字幕菜单根本不会出现在控件栏里;iOS 上还可能需要用户手动长按视频唤出菜单。
关于default属性:
最常被忽略的是服务端响应头和VTT首行格式——这两处出错,整个多语言字幕链就断在源头,连调试入口都没有。



















