字幕显示需同时满足四个条件:track位置正确且为video直接子元素、kind/srclang/label/src四属性齐全合规、WebVTT文件首行严格为“WEBVTT”且UTF-8无BOM、服务端返回text/vtt MIME类型。

track 元素本身不“加载”字幕,它只是声明一个外部 WebVTT 轨道;浏览器是否显示字幕,取决于结构、属性、文件格式、服务端响应四者全部合规——漏一个,字幕菜单里就空着,控制台通常也不报错。
track 必须紧贴 <source></source> 后且是 <video></video> 直接子元素
浏览器只在 <video></video> 开始标签之后、所有 <source></source> 闭合之后、 之前这个狭窄区间内解析 track。放错位置等于没写:
-
track写在<source></source>前面 → 被静默忽略 -
track包在<div> 里或放在 <code>外 →video.textTracks.length恒为 0 - 多个
track之间插了 HTML 注释或空行 → Safari 可能中断后续解析 - 用 JS 动态
appendChild插入 → 失效(<video></video>已完成加载,不会再扫描新track) -
kind="subtitles":必须写全,不能是"subtitle"(少 s)、"captions"(语义不同)或带空格 -
srclang:必须是合法 BCP 47 码,如"zh"、"zh-Hans"、"en-US";"chinese"、"cn"、"pinyin"全部无效 -
label:用户实际看到的菜单名,为空时显示(no label),多语言场景下无法区分;建议含变体说明,如label="中文(简体)" -
src:必须是相对或绝对 URL,不支持 Blob URL;本地开发用file://协议时必失败,得起本地服务(如python3 -m http.server) - 首行必须是顶格、全大写、无空格、无 BOM 的
WEBVTT(写成webvtt或WebVTT都不行) - 时间戳格式必须为
00:00:01.234 --> 00:00:04.567:小时/分钟/秒均两位,毫秒三位,箭头前后各两个空格 - 文件编码必须是 UTF-8 无 BOM(Windows 记事本默认带 BOM,务必用 VS Code 或 Notepad++ 选 “UTF-8 without BOM” 保存)
-
src指向的 .vtt 文件必须返回Content-Type: text/vtt,Nginx/Apache 需显式配置 MIME 类型,否则 Safari 可能拒绝解析 - 正确做法:把翻译和拼音合并进**单个 VTT 文件**,用
<v class="translation"></v>和<v class="pinyin"></v>包裹,并用 CSS 的::cue(.translation)和::cue(.pinyin)分别控制样式 -
srclang="zh-Latn"是标准写法,表示“中文(拉丁字母转写)”,可用于标识拼音轨道;但仅声明不等于自动叠加,仍需合并内容 + CSS 控制 - 若需运行时自由开关翻译/拼音/原文,得禁用原生
track,改用 JS 解析多个 VTT 文件、按时间戳对齐后注入自定义 DOM 层
四个属性 kind、srclang、label、src 缺一不可
浏览器不做任何容错推断。漏任一,该轨道就不会出现在右键字幕菜单中:
WebVTT 文件必须严格合规,错一个字符就全灭
WebVTT 解析器几乎零容错,常见失效点:
立即学习“前端免费学习笔记(深入)”;
双语对照(如翻译+拼音)不能靠两个 track 自动叠加
浏览器默认只激活一个 track。想同时显示两行(如上行为中文翻译、下行为拼音),不能依赖两个独立 track 并行渲染:
最容易被忽略的是:所有环节都必须同时成立——track 位置对、四个属性全、VTT 文件首行和时间戳严丝合缝、服务端返回正确 MIME 和 CORS 头。任何一个点卡住,字幕都不会出现,而且往往没有任何提示。



















