移动端视频字幕需用javascript动态控制生命周期,绕过ios safari等浏览器对静态声明的限制;必须确保html结构合规、vtt格式正确、服务端mime配置到位,并通过texttracks api手动管理显示状态与语言切换。

移动端视频用 <track></track> 动态加载对应字幕,核心不是“加个标签就完事”,而是绕过浏览器对静态声明的限制,用 JavaScript 主动控制轨道生命周期和显示状态。尤其在 iOS Safari 和部分安卓 WebView 中,仅靠 HTML 声明多个 <track></track> 很难实现按需切换或延迟加载——默认菜单可能不出现、default 失效、跨域更敏感。
确保基础结构合规,否则 JS 也救不了
动态加载的前提是 HTML 和 VTT 文件本身无硬伤:
-
<video></video>标签必须带controls属性,Safari 才会渲染字幕控件按钮 - 每个
<track></track>必须作为<video></video>的直接子元素,且严格位于所有<source></source>之后(哪怕只是占位) - VTT 文件首行必须是顶格、全大写、无空格、无 BOM 的 WEBVTT,时间戳格式为
00:00:01.234 --> 00:00:04.567,毫秒三位,编码为 UTF-8 无签名 - 服务端需返回
Content-Type: text/vtt,Nginx/Apache 要显式配置 MIME 类型,否则 iOS Safari 直接拒绝解析
用 JS 动态创建并挂载 track 元素
不依赖 HTML 预置,而是运行时生成 <track></track> 并 append 到 <video></video>,适合按用户语言偏好或网络条件加载:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 先创建新 track:
const track = document.createElement('track'); - 设置必需属性:
track.kind = 'subtitles'; track.srclang = 'zh'; track.label = '中文'; track.src = './sub/zh.vtt'; - 挂载到 video:
video.appendChild(track); - 关键一步:触发加载并启用 —— 等待
track进入loaded状态后,设track.mode = 'showing';;可监听track.onload或轮询track.readyState - 注意:不能把 Blob URL 赋给
src,移动端同样静默忽略;必须用真实 HTTP(S) 路径
手动控制字幕开关与语言切换
移动端原生右键菜单不可用,需自建 UI 按钮,并用 textTracks API 精确干预:
- 获取所有轨道:
const tracks = video.textTracks; - 遍历识别目标语言:
for (const t of tracks) { if (t.kind === 'subtitles' && t.srclang === 'zh') { t.mode = 'showing'; } else { t.mode = 'disabled'; } } - 禁用其他字幕时,务必显式设
mode = 'disabled',不能只设一个为showing;否则多语言下易出现重叠或残留 - 如需自动匹配系统语言,可用
navigator.language或navigator.languages[0]提取语言码(如zh-CN→ 截取zh),再匹配srclang
适配 iOS Safari 的特殊要求
iOS Safari 对字幕支持最苛刻,漏掉任一条件即“菜单消失”:
- 必须至少有一个
<track kind="subtitles" default></track>存在于 HTML 中(哪怕只是空 src),否则控件栏不显示「字幕」按钮 - 动态添加的 track 不会自动出现在右键菜单,但可通过 JS 控制
mode正常显示;用户无法手动点选,所以必须提供自定义语言切换 UI - 若视频使用
playsinline,确保 VTT 加载不受 inline 播放器沙箱影响;建议在canplay事件后执行 track 挂载 - 本地开发测试务必起 HTTP 服务(如
python3 -m http.server),file://协议下 iOS 完全禁用 VTT 加载










