track元素必须嵌套在video/audio标签内且紧随其后,srclang需为有效BCP 47标签,VTT文件须以WEBVTT开头、UTF-8无BOM编码、含空行及毫秒级时间戳。

track元素必须放在video/audio标签内部且紧随其后
浏览器只识别嵌套在媒体元素内部的 <track></track>,放错位置(比如写在 外面或用 JS 动态 append 到 body)会导致完全不加载。它不是独立组件,而是媒体元素的原生子控件。
常见错误现象:DOMException: Failed to execute 'addTextTrack' on 'HTMLMediaElement': The element does not have a parent media element 就是典型的位置错误。
- 正确写法:
<video><track kind="subtitles" src="zh.vtt" srclang="zh" label="中文"></track></video> -
srclang必须是有效 BCP 47 语言标签(如zh-Hans、en-US),否则浏览器可能忽略该 track - 多个
<track></track>可共存,但同一kind(如subtitles)下仅有一个能被激活
字幕文件必须是 WebVTT 格式且编码为 UTF-8
哪怕内容只是简单文字,也必须以 WEBVTT 开头,否则浏览器静默失败,控制台可能无报错,字幕就是不显示。
常见错误现象:字幕轨道出现在右键菜单里可勾选,但勾选后无任何文字出现——八成是 VTT 文件格式或编码问题。
立即学习“前端免费学习笔记(深入)”;
- 最小合法 VTT 示例:
WEBVTT <p>00:00:01.000 --> 00:00:04.000 你好,世界
- 文件保存时务必选 UTF-8(无 BOM),用记事本另存为会默认加 BOM,推荐用 VS Code 或 Sublime Text 编辑
- 路径必须可跨域访问:若 video 在
https://a.com,而src指向http://b.com/zh.vtt,需服务端配 CORS 头Access-Control-Allow-Origin: *
通过 JavaScript 切换字幕要用 textTracks 集合而非 querySelector
textTracks 是媒体元素的实时只读集合,不能用 DOM 方法增删,也不能直接赋值 mode,必须遍历并设 mode 属性。
常见错误现象:调用 document.querySelector('track').mode = 'showing' 无效——因为该 DOM 节点不是实际生效的 track 实例,真正控制权在 video.textTracks[i]。
- 启用指定语言:
const tracks = video.textTracks; for (let i = 0; i < tracks.length; i++) { tracks[i].mode = tracks[i].language === 'zh' ? 'showing' : 'hidden'; } -
mode只有三个值:disabled(默认)、hidden、showing;设showing后浏览器自动匹配当前播放时间戳渲染对应 cue - 监听切换:
video.textTracks.onchange = () => { /* 当前激活 track 改变时触发 */ };
Chrome/Firefox 对自动字幕(kind="captions")和描述(kind="descriptions")支持差异大
如果你的场景是无障碍字幕或音频描述,别默认 kind="subtitles" 通用。不同浏览器对 kind 值的解析逻辑不一致,尤其在右键菜单是否显示、能否通过 JS 控制方面。
-
subtitles:最稳妥,所有现代浏览器均支持手动开启/关闭 -
captions:含音效描述(如 [音乐起]),Firefox 默认不显示在右键菜单,Chrome 支持但需用户手动启用“显示字幕”系统设置 -
descriptions:专为视障用户,仅 Safari 和部分屏幕阅读器支持,JS 中设mode = 'showing'通常无视觉反馈 - 建议:多语言字幕统一用
kind="subtitles",别为了语义准确强行换 kind 值
最容易被忽略的是 VTT 文件的行首空行和时间格式精度——WebVTT 要求 cue 之间至少一个空行,且时间戳必须是 HH:MM:SS.mmm(毫秒三位),写成 00:01:02.5 会被部分浏览器截断或跳过整段。



















