标签仅声明外部文本轨道,不直接添加字幕;字幕显示需同时满足.vtt文件合规、位置紧贴后、服务端响应达标(content-type:text/vtt、同源或cors)、必需属性(kind、src、srclang)合法四条件。

<track></track> 标签本身不“添加字幕”,它只是声明一条外部文本轨道;字幕能否显示,取决于 .vtt 文件是否合规、位置是否正确、服务端响应是否达标——四个条件缺一不可,否则静默失败,连控制台都不报错。
track 元素必须严格嵌套在 video 内且紧贴 source 之后
浏览器只认一种结构:从 <video></video> 开始,接着是零个或多个 <source></source>,然后才是 <track></track>,最后闭合 。放错位置等于没写。
- ❌ 错误:把
<track></track>放在<source></source>前面,或写在外面,或包在<div> 里 <li>❌ 错误:在 <code><source></source>和<track></track>之间插入注释、空行或其它标签(部分浏览器会中断解析) - ✅ 正确顺序示例:
<video controls><br><source src="movie.mp4" type="video/mp4"><br><track kind="subtitles" src="zh.vtt" srclang="zh" label="中文" default><br></track></source></video>
- 首行必须是
WEBVTT(全大写、无空格、无缩进、无 UTF-8 BOM) - 时间戳格式严格为
00:00:01.234 --> 00:00:04.567(毫秒必须三位,箭头前后各一个空格) - 文件编码必须为 UTF-8 无 BOM;用记事本保存时选“UTF-8”而非“UTF-8 with BOM”
- 别用 SRT 改后缀:SRT 的序号+空行分隔方式不被 WebVTT 解析器识别,必须用工具(如
vtt-tools或在线转换器)转成标准 VTT - 本地开发时,
file://协议下<track></track>必然失效(Chrome/Firefox 明确禁用),必须起本地服务(如python3 -m http.server) - 服务器需返回
Content-Type: text/vtt;Nginx 示例配置:types { text/vtt vtt; } - 若视频在 HTTPS 页面,
src必须也是 HTTPS;跨子域需服务端配Access-Control-Allow-Origin头,否则 Network 面板显示net::ERR_BLOCKED_BY_RESPONSE - 路径区分大小写:
zh.vtt≠ZH.VTT(尤其在 Linux 服务器上) -
kind是必填项,且只能是"subtitles"(注意复数 s),写成"subtitle"或漏掉,该<track></track>直接被忽略 -
srclang必须是合法 BCP 47 语言码,如"zh"、"en-US"、"ja";写成"chinese"或空字符串,会导致多语言切换失效 -
default只能出现在一个<track></track>上;多个时,多数浏览器只启用第一个,其余静默降级为disabled -
label虽非强制,但建议填写——它是用户在播放器字幕菜单里看到的唯一名称
WebVTT 文件必须满足三项硬性规范
哪怕一个空格出错,整条轨道都会被浏览器丢弃——不是“显示异常”,而是彻底不加载。
src 路径与服务端响应必须匹配
<track src="..."></track> 是一次独立 HTTP 请求,和图片、脚本一样受跨域和 MIME 类型限制。
必需属性一个都不能少,且值必须合法
浏览器对属性缺失或非法值极其敏感,常表现为字幕菜单为空、或轨道根本不注册进 video.textTracks。
最易被忽略的是:即使所有代码都写对,用户也得手动点击播放器上的“字幕”按钮并选择对应轨道,默认并不自动弹出;而 default 属性只在用户未主动关闭字幕时生效,一旦用户点过“关闭”,下次刷新页面也不会恢复。这层交互逻辑,无法靠 HTML 属性绕过。











