VTT 文件是什么?WebVTT 格式、真实示例,以及浏览器实际显示了什么
VTT(WebVTT)是网页视频的字幕格式。本文讲清格式和真实示例,并实测 Chrome 与 Safari 对 17 项功能、18 种损坏文件的处理。
VTT 文件(扩展名 .vtt,全称 WebVTT,Web Video Text Tracks)是网页视频用的字幕格式。
它和 SRT 一样是纯文本:一串字幕条目(cue),每条有开始时间、结束时间和要显示的文字。
在此之外,它还能带定位、样式和注释。HTML5 的 <track> 元素只接受这一种字幕格式,所以网页里的视频播放器都认它。
大多数介绍写到"VTT 支持样式和定位"就结束了。我们想知道这些附加功能到底能不能显示出来,于是每个功能单独写一个测试文件,分别在 Chrome 155 和 Safari 26.2 里播放,其中 5 个还在 iPhone 上播放了一遍。 然后又把 VTT 文件按 18 种常见方式改坏,交给两个浏览器、ffmpeg 和我们自己的转换器处理。结果在格式介绍之后。
VTT 文件长什么样
下面是一个真实文件的前三条:ScribeToAny 给教程里那段 64 秒面包店采访生成的字幕。 内容和我们 SRT 示例里的完全一样,只是导出成了 VTT。
WEBVTT
00:00:00.000 --> 00:00:01.680
Welcome back to Small Shop Stories.
00:00:02.160 --> 00:00:05.320
Today I'm talking to Maya, who runs a tiny bakery on the
00:00:05.320 --> 00:00:06.320
corner of Mill Street.
VTT 文件由两类块组成,块之间用空行隔开:
- 文件头。 文件必须以大写的
WEBVTT开头。同一行后面可以空一格再写说明(WEBVTT - Kitchen interview),然后是一个空行。 - 字幕条目。 每条依次是:可选的标识行、时间行、一行或多行文字。时间行写作
开始 --> 结束,毫秒前用点号:00:00:05.320就是 5.32 秒。小时可以省略,所以00:05.320也合法。结束时间后面同一行的内容是字幕设置,比如line:0。
文件必须是 UTF-8 编码,没有别的选项。
字幕条目之间还可以出现三种块:NOTE(注释,永远不显示)、STYLE(给字幕用的 CSS)、REGION(屏幕上一块有名字的区域,字幕可以在里面滚动)。
VTT 和 SRT 的区别
字幕文字本身通常一模一样,所以普通字幕在两者之间转换不会丢东西。区别都在文字外面:
| VTT | SRT | |
|---|---|---|
| 第一行 | WEBVTT(必需) | 序号 1 |
| 毫秒分隔符 | 点号:00:00:05.320 | 逗号:00:00:05,320 |
| 序号 | 可选的标识,任意文字 | 默认要有,1、2、3…… |
| 时间里的小时 | 可省略 | 必需 |
| 定位 | 字幕设置(line、position、align、size、vertical) | 格式里没有 |
| 样式 | <b>、<i>、<u>、class、说话人、STYLE 块里的 CSS | <b>、<i>、<u>,很多播放器还认 <font> |
| 注释 | NOTE 块 | 无 |
| 能在网页里播放 | 能,通过 <track> | 不能 |
| 规范 | W3C | 无 |
简单说:视频在浏览器里播放就用 VTT;要进剪辑软件、电视或桌面播放器,就用 SRT。其他格式见 字幕与转录文件格式。
浏览器实际显示了什么:17 项 VTT 功能实测
每个功能写一个小 VTT 文件,用本地 Web 服务器提供,放进 <video> 的 <track> 里加载。
每次测试都跳到字幕应该出现的时间点,截下视频画面,再通过页面的 textTracks 接口读出浏览器实际解析到了什么。
Chrome 用全新的临时配置以无界面模式运行,结果异常的几项又在有窗口的 Chrome 里重测了一遍;Safari 通过 safaridriver 自动操作。系统都是 macOS 26.2。
| 功能 | Chrome 155 | Safari 26.2 |
|---|---|---|
| 普通字幕、NOTE 块、条目标识、不写小时的时间 | ✅ | ✅ |
line:0(顶部)、line:50%(中间) | ✅ | ✅ |
position:10% align:start size:40% | ✅ | ✅(换行框更窄) |
vertical:rl(竖排) | ✅ | ✅ |
<b>、<i>、<u> | ✅ | ✅ |
STYLE 块:::cue 的颜色、字体、字号 | ✅ | ✅ |
class:<c.yellow> 配 ::cue(.yellow) | ✅ | ✅ |
说话人:<v Maya> 配 ::cue(v[voice="Maya"]) | ✅(不显示名字) | ✅(不显示名字) |
字符引用(&、<、 ) | ✅ | ✅ |
用 <lang ja> 包住的日文和中文 | ✅ | ✅ |
<ruby> 注音 | ✅ | ⚠️ 注音单独占一行 |
卡拉 OK 时间标签配 ::cue(:past) / :future | ❌ 不变色 | ❌ 不变色 |
REGION(lines:3、scroll:up) | ❌ 被忽略 | ⚠️ 画出了区域,第四行始终没滚进来 |
| 四条时间重叠的字幕,拖动进度条跳进去之后 | ⚠️ 只显示第一条 | ✅ 四条都显示 |

功能测试说明了什么
日常用到的功能都靠得住。 定位、粗体斜体、STYLE 块里的颜色和字体、class 和说话人样式,在两个浏览器里显示一致。
如果字幕要放到画面顶部、避免挡住下方的字幕条,line:0 可以放心用。
iPhone 和 Mac 结果一致。 我们在 iPhone 的 Safari 里播放了其中 5 个测试文件,页面内和全屏各看一次:定位、STYLE 块的颜色和字体、class、注音,以及四条重叠字幕。全屏也保留了样式,注音和 Mac 上的 Safari 一样单独占一行。
区域和卡拉 OK 还不能用。 Chrome 完全不管区域:textTracks 接口里每条字幕的区域都是空的,字幕照常堆在底部。
卡拉 OK 的逐词变色,两个浏览器都没有生效,暂停和播放时都一样。
Chrome 在拖动进度条后会漏掉重叠字幕。 这一条出乎我们意料。两个人同时说话时,字幕文件里常有时间重叠的条目。
从头播放四条重叠字幕,Chrome 能全部显示;但像观众拖动进度条那样直接跳到它们中间,Chrome 只显示开始最早的那一条,它的 activeCues 列表也只有这一条。
只有两条重叠、或者各条结束时间不同,结果都一样。Safari 在每种情况下都显示了全部字幕。
如果你的字幕有重叠,请在 Chrome 里拖动进度条测一测,或者把重叠部分拆成前后相接的独立条目。
YouTube 更严格。 YouTube 帮助文档把 WebVTT 列为"高级"格式:支持定位,但样式只认 <b>、<i>、<u>。class 和 STYLE 块上传后不会保留。
VTT 字幕为什么不显示:我们把文件改坏了 18 种方式
报错的文件会有人去修。危险的是另一种:视频照常播放,什么提示都没有,字幕就是不出来。 我们拿一个正常的两条字幕文件,按 18 种方式改坏,每个版本都交给 Chrome、Safari、ffmpeg 8.1.1(转成 SRT)和 ScribeToAny 的字幕转换器处理。后者是我们免费 VTT 工具背后的解析器。
"报错"指浏览器触发了字幕轨的 error 事件,开发者至少还能捕获到。"静默"指字幕轨显示加载成功、里面却什么都没有,或者丢了内容却没有任何提示。
| 文件的问题 | Chrome 155 | Safari 26.2 | ffmpeg 8.1.1 | ScribeToAny |
|---|---|---|---|---|
| 没问题(正常文件) | ✅ | ✅ | ✅ | ✅ |
| 开头有 BOM | ✅ | ✅ | ✅ | ✅ |
| Windows 换行(CRLF) | ✅ | ✅ | ✅ | ✅ |
文件头写成 WEBVTT - 标题 | ✅ | ✅ | ✅ | ✅ |
| 箭头两边没有空格 | ✅ | ✅ | ✅ | ✅ |
小时只有一位(0:00:05.000) | ✅ | ✅ | ✅ | ✅ |
| 条目之间没有空行 | ✅ | ✅ | ✅ | ✅ |
没有 WEBVTT 文件头 | ❌ 报错 | ❌ 报错 | ✅(有警告) | ✅ |
文件头写成小写 webvtt | ❌ 报错 | ❌ 报错 | ❌ 什么都没读到 | ✅ |
SRT 文件直接改名成 .vtt | ❌ 报错 | ❌ 报错 | ✅ 当作 SRT 读 | ✅ |
| 毫秒前用了逗号 | ❌ 静默:0 条字幕 | ❌ 静默:0 条字幕 | ❌ 什么都没读到 | ✅ |
毫秒只写两位(05.32) | ❌ 静默:0 条字幕 | ❌ 静默:0 条字幕 | ✅ | ✅ |
WEBVTT 后面没有空行 | ✅ | ✅ | ⚠️ 静默:第一条丢失 | ✅ |
| 字幕文字中间夹了一个空行 | ⚠️ 静默:空行后的文字丢失 | ⚠️ 静默:空行后的文字丢失 | ⚠️ 静默:连下一条也丢了 | ⚠️ 与浏览器相同 |
| 结束时间早于开始时间 | ⚠️ 这条永远不显示 | ⚠️ 这条永远不显示 | ❌ 结束时间写成了 1193:03:02,296 | ⚠️ 原样保留,编辑器的质量检查会标出 |
| 存成 Latin-1 编码("café") | ⚠️ 乱码:caf� | ⚠️ 乱码:caf� | ⚠️ 静默:这条被丢弃 | ✅ 自动识别编码 |
SRT 的标签 <font color>、{\an8} | {\an8} 当文字显示 | {\an8} 当文字显示 | {\an8} 被改乱 | {\an8} 被移除 |
以 text/plain 而不是 text/vtt 返回 | ✅ | ✅ | 不适用 | 不适用 |
| 放在别的域名、没有 CORS 头 | ❌ 报错 | ✅ 能播放 | 不适用 | 不适用 |
坏文件测试说明了什么
时间里的逗号是最经典的坑。 把 SRT 改个扩展名,或者只补了文件头没改时间,就会这样。
两个浏览器都接受了文件、报告加载成功,然后一条字幕都不显示。毫秒只写两位也是同样的结果。
如果 VTT 字幕轨"加载了"但什么都不出来,先查时间行:00:00:05.320,点号,加三位毫秒。
浏览器对文件头很严格,对其他地方都很宽松。 没有文件头或写成小写,字幕轨直接失败。
条目间缺空行、BOM、CRLF 换行、一位数的小时、text/plain 类型,都没有问题。
跨域文件在不同浏览器里表现不同。 同一个正常文件放在别的域名、不带 CORS 头,Safari 能播放,Chrome 失败。
也就是说,页面在你测试用的 Mac 上一切正常,Chrome 用户却看不到字幕。
解决办法是把 .vtt 和页面放在同一个域名下;或者让服务器返回 Access-Control-Allow-Origin 头,同时给 <video> 加上 crossorigin 属性。两样都做了以后,Chrome 就能加载。
转换 VTT 可能会悄悄改掉内容。 ffmpeg 把一个早于开始时间的结束时间,在输出的 SRT 里写成了 1193:03:02,296;
文件头后面缺空行时,它丢掉了第一条;遇到字幕文字中间的空行,它把后面整条字幕都丢了。转换完记得对一下输入和输出的条目数。
我们自己的转换器也有 VTT 的问题,这次测试把它抓了出来。 上面每一个坏文件它都能读进去,但它会把 VTT 专用的标记留在文字里。
把说话人测试文件转成 TXT,得到的是 <v Maya>Voice tag…</v>,& 也原样输出,没有还原成 &。
卡拉 OK 时间标签和 <ruby> 注音也以同样方式漏进了 TXT、Word、PDF 和 SRT 输出。
我们当天修好了:VTT 字幕文字现在会去掉只有浏览器才懂的标签(<c>、<v>、<lang>、<ruby> 的注音、卡拉 OK 时间标签),保留 SRT 同样支持的 <b>、<i>、<u>,并还原字符引用。这些情况都加进了我们的回归检查。
我们没测的: 只测了一台 Mac 上的两个桌面浏览器和一个 ffmpeg 版本,用的是很小的合成文件。 Firefox、Android、智能电视和 VLC 这类播放器都有自己的 WebVTT 实现,结果可能不同。 iPhone 上只测了 17 项里的 5 项,也没有测拖动进度条。
怎么打开、制作和转换 VTT 文件
- 查看内容: 任何纯文本编辑器都行,比如记事本或 TextEdit。
- 跟视频一起看: 大多数桌面播放器能在视频旁边加载它。在网页里,把
<track kind="subtitles" srclang="en" src="file.vtt">放进<video>元素。如果字幕包含声音描述,用kind="captions";两者的区别见隐藏式字幕与普通字幕。 - 从录音生成: 把音频或视频上传到字幕生成器,导出 VTT。
- 格式转换: SRT 转 VTT 会补上文件头、把逗号换成点号;VTT 转 SRT 反过来;VTT 转文本 只保留文字。三个工具都在浏览器里运行,文件不会上传。
- 修复文件: 用 SRT 编辑器打开,它也能读 VTT,会标出结束早于开始、或者快得来不及读的字幕。改好后另存一份干净的文件。
常见问题
VTT 的 MIME 类型是什么? text/vtt。服务器上还是应该设好,尽管在我们的测试里,Chrome 155 和 Safari 26.2 对以 text/plain 返回的文件也能正常播放。
VTT 比 SRT 好吗? 网页视频用 VTT 更好,因为浏览器只认 VTT。其他场合 SRT 更稳妥:支持它的剪辑软件、电视和上传表单更多。
能直接把 .srt 改名成 .vtt 吗? 不能。两个浏览器都拒绝了改名后的文件。你需要加上 WEBVTT 文件头,并把逗号换成点号,SRT 转 VTT 做的就是这件事。
VTT 文件就是加了文件头、把逗号换成点号、还能放附加功能的 SRT。 基础功能在我们测过的地方都正常;附加功能要看浏览器,而最糟的故障都是静默的:时间里的一个逗号、放在别的域名上的文件、跳进重叠字幕的一次拖动。 时间行写准确,文件放在自己的域名下,上线前在不止一个浏览器里播一遍。