track标签本身不添加字幕,仅声明外部webvtt轨道;必须满足四重条件:紧贴source后的video直接子元素、kind/srclang/label缺一不可、webvtt文件首行全大写无bom且时间戳毫秒三位、服务端返回text/vtt mime类型。

直接把 <track></track> 写进 <video></video> 里不等于字幕就出来了——结构错一环,整个多语言菜单就空着,连报错都没有。
track 必须是 video 的直接子元素且位置固定
浏览器只在 <video></video> 开始标签之后、所有 <source></source> 闭合之后、 之前解析 <track></track>。放错位置(比如塞进 <div> 里、写在 <code> 外面、夹在两个 <source></source> 中间)等于没写。
-
<track></track>不能用 JS 动态插入到已渲染的<video></video>内部——必须随 HTML 一起加载 - 多个
<track></track>可并列,但中间不能插注释或空行(部分浏览器会中断解析) - 移动端 Safari 要求
<video></video>带controls属性,否则字幕菜单根本不出现在控件栏
kind、srclang、label 三者缺一不可
浏览器靠这三项硬性匹配并生成右键菜单选项。漏掉任意一个,对应轨道就不会出现在 UI 中,不是“不显示”,而是“菜单里压根没有”。
-
kind="subtitles":必须全小写、拼写完整,kind="caption"或kind="subtitles "(末尾空格)都会失效 -
srclang:必须是合法 BCP 47 码,如"zh"、"en-US"、"ja";"chinese"、"zh_CN"、空值均被忽略 -
label:用户看到的名称,建议含括号注明变体,如"中文(简体)";为空时可能显示(no label),多语言场景下无法区分 -
default:仅允许在一个<track></track>上设置,多个会导致行为未定义(多数浏览器只启用第一个)
WebVTT 文件格式容错率近乎为零
哪怕只错一个字符,Chrome/Firefox 就静默丢弃整条轨道——控制台不报错、Network 面板看不到请求失败、字幕菜单空白。
- 首行必须是顶格、全大写、无空格、无 BOM 的
WEBVTT - 时间戳格式严格为
00:00:01.234 --> 00:00:04.567:小时/分/秒两位,毫秒三位,中间两个空格 - 文件编码必须是 UTF-8 无 BOM;Windows 记事本默认带 BOM,务必用 VS Code / Sublime / Notepad++ 保存为 “UTF-8 without BOM”
- 服务器需返回
Content-Type: text/vtt;若返回text/plain或application/octet-stream,部分浏览器拒绝加载
src 路径与跨域问题常被忽略
路径看似简单,但本地开发和上线后最容易在这里断链。浏览器对 <track src="..."></track> 的请求是独立发起的,和视频本身无关。
- 相对路径以 HTML 文件所在 URL 为基准,不是 JS 或 CSS 所在目录
- 本地用
file://协议时,<track></track>几乎必然失效(Chrome/Firefox 默认禁用跨文件请求),必须起本地服务(如python3 -m http.server) - 跨域时,服务端必须返回
Access-Control-Allow-Origin: *;否则 Firefox/Edge 静默失败,Network 面板显示Blocked: CORS - 不要用 SRT 文件直接赋给
src——浏览器不认,也不会报错;必须转成 WebVTT 格式(可用ffmpeg -i input.srt output.vtt)
真正难的不是写几行 HTML,而是四个环节全部对齐:VTT 文件合规、HTML 结构精准、属性声明完整、服务端响应正确。任一环节出错,字幕都不会出现在菜单里——不是错位,是彻底消失。











