default属性不可靠,浏览器不保证默认开启字幕;仅当用户首次访问、未操作过字幕开关且满足srclang、kind、MIME类型等全部隐性条件时才可能生效;真正可控的方式是JS在loadedmetadata后检查readyState并设mode="showing"。

default 属性根本不可靠
加了 default 却没显示字幕,不是你写错了,而是浏览器压根没打算按你想的执行。它既不保证“默认开启”,也不等于“用户一打开就看见字幕”。真实行为是:仅当用户首次访问、从未点过字幕开关、且浏览器恰好支持该逻辑时,才可能把对应 track 的 mode 设为 "showing"。Safari(尤其 iOS)基本无视 default;Chrome 也只在无操作历史时兜底一次;刷新页面后若用户之前关过字幕,default 就彻底失效。
为什么 default 常见失效
常见原因不是代码漏写,而是隐性条件全不满足:
-
srclang值不合法,比如写成"zh-CN",但用户系统语言是"zh",或拼错为"chinese" - 多个
<track></track>都写了default→ 多数浏览器直接忽略全部,或只启用第一个(行为未定义) -
kind不是"subtitles"(例如用了"captions"或"descriptions"),Safari 就不走 default 逻辑 -
src指向的 .vtt 文件返回 404、CORS 错误,或服务端没返回text/vttMIME 类型 → 轨道加载失败,default失去作用对象 - 视频还没触发
loadedmetadata事件,video.textTracks还为空,浏览器根本来不及处理default
真正可控的默认启用方式:JS 主动设 mode
必须等 loadedmetadata 触发后,遍历 video.textTracks 找目标轨道再设 mode = "showing":
video.addEventListener('loadedmetadata', () => {
const lang = navigator.languages?.[0] || document.documentElement.lang || 'zh';
const targetTrack = Array.from(video.textTracks).find(track =>
track.kind === 'subtitles' &&
(track.srclang === lang || track.srclang.startsWith(lang.split('-')[0]))
);
if (targetTrack && targetTrack.readyState === 2) {
targetTrack.mode = 'showing';
Array.from(video.textTracks)
.filter(t => t !== targetTrack && t.kind === 'subtitles')
.forEach(t => t.mode = 'disabled');
}
});
注意三点:
立即学习“前端免费学习笔记(深入)”;
-
textTracks是实时集合,必须等loadedmetadata后才能安全遍历 - 设
mode前先检查track.readyState === 2(即TextTrack.LOADED),否则静默失败 - 移动端 Safari 默认隐藏原生字幕按钮,即使 JS 设了
mode,用户也看不到 UI——得自己渲染字幕开关并绑定 click 事件
本地开发和部署最容易踩的坑
本地用 file:// 协议打开 HTML,所有 .vtt 加载都会因 CORS 静默失败;服务器没配 text/vtt MIME 类型,Safari 直接跳过解析;<track></track> 没放在 <source></source> 之后、 之前,会被浏览器忽略。务必用 python3 -m http.server 或类似服务启动本地预览,并在 DevTools Network 面板确认 .vtt 返回 200、Content-Type 是 text/vtt。



















