track标签本身不添加字幕,仅声明外部文本轨道;字幕显示需同时满足结构位置正确(video内紧贴source后)、属性完整(kind/srclang/label缺一不可)、WebVTT文件合规(首行WEBVTT、UTF-8无BOM、时间戳格式严格)、服务端响应达标(Content-Type: text/vtt、同源或CORS)四条件。

track 标签本身不添加字幕,它只是向 video 元素声明一条外部文本轨道;字幕能否显示,取决于四个条件是否同时满足:结构位置正确、属性完整合法、.vtt 文件格式合规、服务端响应达标。漏掉任意一个,浏览器通常静默失败——控制台可能没报错,但字幕菜单为空或根本不出现在右键菜单里。
track 必须是 video 的直接子元素且紧贴 source 之后
浏览器只在video 开始标签后、所有 source 闭合之后、 之前识别 track。放错位置等于没写,且多数浏览器不报错。
- ❌ 错误:把
<track></track>写在<video></video>外面、包在<div> 里、插在 <code><source></source>前面 - ❌ 错误:在
<source></source>和<track></track>之间加空行、注释或其它标签(部分浏览器会中断解析) - ✅ 正确顺序示例:
<video controls> <source src="movie.mp4" type="video/mp4"> <track kind="subtitles" src="zh.vtt" srclang="zh" label="中文" default> </video>
-
kind="subtitles"必须显式写出;"subtitle"或空值会被忽略 -
srclang在kind="subtitles"时强制要求,必须是合法 BCP 47 码(如"zh"、"en-US"),不能是"ch"或"english" -
label是用户在播放器字幕菜单中看到的名字;为空时可能显示"(no label)",多语言场景下无法区分 - 首行必须是
WEBVTT(全大写、顶格、前后无空格、无 UTF-8 BOM) -
WEBVTT后必须紧跟一个空行(\n\n,不是\r\n或空格) - 时间戳格式为
00:00:01.234 --> 00:00:04.567:毫秒位必须三位,箭头前后各一个空格 - 文件编码必须为 UTF-8 无 BOM;VS Code 保存时选 “UTF-8”,不要选 “UTF-8 with BOM”
- 本地开发时,
file://协议下track必然失效(Chrome/Firefox 明确禁用),必须起本地服务(如python3 -m http.server) - 服务器必须返回
Content-Type: text/vtt;Nginx 示例配置:types { text/vtt vtt; } - 路径区分大小写:
zh.vtt≠ZH.VTT(尤其 Linux 服务器) - 若视频在 HTTPS 页面,
src也必须是 HTTPS;跨子域需服务端配Access-Control-Allow-Origin
kind、srclang、label 这三个属性缺一不可
它们不是“可选优化”,而是浏览器注册轨道的硬性门槛。缺少任一,video.textTracks.length 可能为 0,字幕菜单里也看不到该条目。
.vtt 文件首行和时间戳格式极其严格
Chrome/Firefox/Edge 对 WebVTT 解析非常苛刻:一个空格、一个换行、一个 BOM 都会导致整条轨道被丢弃,且控制台仅提示模糊的Failed to parse WebVTT。
src 路径与服务端响应必须匹配
<track src=""></track> 是一次独立 HTTP 请求,受同源策略、CORS、MIME 类型限制,和加载 JS/CSS 一样敏感。
真正容易被忽略的是:所有检查都通过后,字幕仍不显示,大概率是因为用户没在播放器控件里手动点开「字幕」按钮并选择对应轨道——default 属性只影响首次加载时的启用状态,且前提是用户此前未手动关闭过字幕。



















