这篇文章也在 MDN 上提供。
随着 <video> 和 <audio> 元素引入 HTML5,我们终于有了在网站上添加视频和音频的原生方式。我们还有 JavaScript API 允许我们以不同的方式与这种媒体内容交互,无论是编写我们自己的控件还是简单地查看视频文件的长度。作为负责任的网页开发者,我们也应该不断思考如何使我们的内容更易访问,这并不止于视频和音频内容。使我们的内容对所有人来说更易访问是一项重要步骤,无论对于听力障碍者还是不理解内容所用语言的人,包容性都至关重要。
幸运的是,HTML5 还通过 <track> 元素为我们提供了一种原生方式来使我们的媒体内容更易访问,方法是添加字幕。大多数主流浏览器都以不同程度的方式原生支持这一点,本文的第一部分对此进行了说明,但也提供了一个 JavaScript API,我们可以通过该 API 访问和使用可用的文本轨道(例如字幕)。本文还展示了如何使用此 API 来检测已添加到 HTML5 视频中的字幕,以及如何使用这些数据来构建可选择的可用文本轨道菜单,最终为各种浏览器提供更一致的界面。
在 MDN 的文章中,我们已经了解了如何使用 构建跨浏览器视频播放器,使用 HTMLMediaElement
和 Window.fullScreen
API,以及如何 设置播放器的样式。本文将采用同一个播放器,并展示如何使用 Web_Video_Text_Tracks_Format
和 <track>
元素向其中添加字幕。
带字幕的视频示例
在本文中,我们将参考带字幕的视频播放器示例。此示例使用 Sintel 开放电影 的片段,该电影由 Blender 基金会 创建。
注意:你可以在 Github 上找到源代码,还可以 查看示例的实时演示。
HTML5 和视频字幕
在深入了解如何向视频播放器添加字幕之前,我们先提几点需要注意的事项。
字幕和旁白
字幕和旁白并非一回事:它们针对的受众截然不同,传递的信息也不同,如果你不确定它们的区别,建议你阅读一下。然而,它们在技术上以相同的方式实现,因此本文中的内容适用于两者。
在本文中,我们将参考显示为字幕的文本轨道,因为它们的内容针对的是有听力但难以理解电影语言的人,而不是聋人或听力障碍者。
<track> 元素
HTML5 允许我们使用 <track>
元素为视频指定字幕。该元素的各种属性允许我们指定诸如添加的内容类型、内容所用语言,以及当然,对包含实际字幕信息的文本文件的引用等。
WebVTT
包含实际字幕数据的文件是遵循指定格式的简单文本文件,在本例中,格式为 Web 视频文本轨道 (WebVTT) 格式。 WebVTT 规范 仍在开发中,但其主要部分已稳定,因此我们今天就可以使用它。
视频提供商(例如 Blender 基金会)会以文本格式提供字幕,但通常以 SubRip Text (SRT) 格式提供。可以使用在线转换器(例如 srt2vtt)轻松地将它们转换为 WebVTT。
对 HTML 和 CSS 的修改
本节总结了对上一篇文章代码进行的修改,以便为视频添加字幕。如果你对这些内容不感兴趣,只想直接进入 JavaScript 和更相关的 CSS,请跳到 字幕实现 部分。
在本示例中,我们使用的是不同的视频,Sintel,因为它实际上包含了一些语音,因此更适合用来说明字幕的工作原理!
HTML 标记
如上所述,我们需要使用新的 HTML5 <track>
元素将字幕文件添加到 HTML5 视频中。我们的字幕实际上有三种不同的语言——英语、德语和西班牙语——因此我们将通过在 HTML5 <video>
元素中添加 <track>
元素来引用所有三个相关的 VTT 文件
<video id="video" controls preload="metadata">
<track label="English" kind="subtitles" srclang="en" src="subtitles/vtt/sintel-en.vtt" default>
<track label="Deutsch" kind="subtitles" srclang="de" src="subtitles/vtt/sintel-de.vtt">
<track label="Español" kind="subtitles" srclang="es" src="subtitles/vtt/sintel-es.vtt">
</video>
如你所见,每个 <track>
元素都设置了以下属性
kind
的值为subtitles
,表示文件包含的内容类型label
的值为指示字幕集的语言,例如English
或Deutsch
——这些标签将出现在用户界面中,以便用户轻松选择要查看的字幕语言。src
被分配了一个指向每个相关 WebVTT 字幕文件的有效 URL。srclang
指示每个字幕文件的语言。default
属性在英语<track>
元素上设置,表示浏览器在字幕已打开且用户未进行特定选择时,应使用此默认字幕文件定义。
除了添加 <track>
元素之外,我们还添加了一个新按钮来控制我们将要构建的字幕菜单。因此,视频控件现在如下所示
<div id="video-controls" class="controls">
<button id="playpause" type="button">Play/Pause</button>
<button id="stop" type="button">Stop</button>
<div class="progress">
<span id="progress-bar"></span>
</div>
<button id="mute" type="button">Mute/Unmute</button>
<button id="volinc" type="button">Vol+</button>
<button id="voldec" type="button">Vol-</button>
<button id="fs" type="button">Fullscreen</button>
<button id="subtitles" type="button">CC</button>
</div>
CSS 更改
视频控件经过了一些细微的更改,以便为额外的按钮腾出空间,但这些更改相对简单。
字幕按钮不使用任何图像,因此它只是按以下方式设置样式
.controls button[data-state="subtitles"] {
height:85%;
text-indent:0;
font-size:16px;
font-size:1rem;
font-weight:bold;
color:#666;
background:#000;
border-radius:2px;
}
还有一些其他 CSS 更改特定于一些额外的 JavaScript 实现,但这些将在下面适当的地方提到。
字幕实现
我们用来访问视频字幕的很多内容都与 JavaScript 有关。与视频控件类似,如果浏览器支持 HTML5 视频字幕,将在原生控件集中提供一个按钮来访问它们。但是,由于我们定义了自己的视频控件,因此此按钮被隐藏,我们需要自己定义一个。
浏览器对所支持的功能存在差异,因此我们将尝试尽可能地为每个浏览器提供更统一的 UI。有关浏览器兼容性问题的更多信息,请参见后面的内容。
初始设置
与所有其他按钮一样,我们需要做的第一件事之一是存储对字幕按钮的句柄
var subtitles = document.getElementById('subtitles');
我们还最初关闭所有字幕,以防浏览器默认打开其中任何一个
for (var i = 0; i < video.textTracks.length; i++) {
video.textTracks[i].mode = 'hidden';
}
video.textTracks
属性包含与视频关联的所有文本轨道的数组。我们循环遍历每个轨道,并将它们的 mode
设置为 hidden
。
注意: WebVTT API 允许我们使用 <track>
元素访问为 HTML5 视频定义的所有文本轨道。
构建字幕菜单
我们的目标是使用我们之前添加的 subtitles
按钮来显示一个菜单,允许用户选择要显示的字幕语言,或者完全关闭字幕。
我们已经添加了按钮,但在让它执行任何操作之前,我们需要为它构建菜单。此菜单是动态构建的,因此可以稍后通过简单地编辑视频标记中的 <track>
元素来添加或删除语言。
我们所需要做的就是遍历视频的 textTracks
,读取它们的属性,并从那里构建菜单
var subtitlesMenu;
if (video.textTracks) {
var df = document.createDocumentFragment();
var subtitlesMenu = df.appendChild(document.createElement('ul'));
subtitlesMenu.className = 'subtitles-menu';
subtitlesMenu.appendChild(createMenuItem('subtitles-off', '', 'Off'));
for (var i = 0; i < video.textTracks.length; i++) {
subtitlesMenu.appendChild(createMenuItem('subtitles-' + video.textTracks[i].language, video.textTracks[i].language, video.textTracks[i].label));
}
videoContainer.appendChild(subtitlesMenu);
}
此代码创建一个 <a href=”https://mdn.org.cn/en-US/docs/Web/API/documentFragment” title=”The DocumentFragment interface represents a minimal document object that has no parent. It is used as a light-weight version of Document to store well-formed or potentially non-well-formed fragments of XML.” documentFragment
,用于保存包含字幕菜单的无序列表。首先,添加一个选项允许用户关闭所有字幕,然后为每个文本轨道添加按钮,从每个轨道读取语言和标签。
每个列表项和按钮的创建由 createMenuItem()
函数完成,该函数定义如下
var subtitleMenuButtons = [];
var createMenuItem = function(id, lang, label) {
var listItem = document.createElement('li');
var button = listItem.appendChild(document.createElement('button'));
button.setAttribute('id', id);
button.className = 'subtitles-button';
if (lang.length > 0) button.setAttribute('lang', lang);
button.value = label;
button.setAttribute('data-state', 'inactive');
button.appendChild(document.createTextNode(label));
button.addEventListener('click', function(e) {
// Set all buttons to inactive
subtitleMenuButtons.map(function(v, i, a) {
subtitleMenuButtons[i].setAttribute('data-state', 'inactive');
});
// Find the language to activate
var lang = this.getAttribute('lang');
for (var i = 0; i < video.textTracks.length; i++) {
// For the 'subtitles-off' button, the first condition will never match so all will subtitles be turned off
if (video.textTracks[i].language == lang) {
video.textTracks[i].mode = 'showing';
this.setAttribute('data-state', 'active');
}
else {
video.textTracks[i].mode = 'hidden';
}
}
subtitlesMenu.style.display = 'none';
});
subtitleMenuButtons.push(button);
return listItem;
}
此函数构建所需的 <li>
和 <button>
元素,并将它们返回,以便它们可以添加到字幕菜单列表中。它还在按钮上设置了所需的事件侦听器,以切换相关字幕集的显示或隐藏。这只需将所需字幕的 mode
属性设置为 showing
,并将其他字幕的 mode
属性设置为 hidden
即可。
构建菜单后,它将被插入到视频容器底部的 DOM 中。
最初,菜单默认情况下是隐藏的,因此需要在字幕按钮上添加一个事件侦听器来切换它
subtitles.addEventListener('click', function(e) {
if (subtitlesMenu) {
subtitlesMenu.style.display = (subtitlesMenu.style.display == 'block' ? 'none' : 'block');
}
});
字幕菜单 CSS
我们还为新创建的字幕菜单添加了一些基本的样式
.subtitles-menu {
display:none;
position:absolute;
bottom:14.8%;
right:20px;
background:#666;
list-style-type:none;
margin:0;
padding:0;
width:100px;
padding:10px;
}
.subtitles-menu li {
padding:0;
text-align:center;
}
.subtitles-menu li button {
border:none;
background:#000;
color:#fff;
cursor:pointer;
width:90%;
padding:2px 5px;
border-radius:2px;
}
设置显示字幕的样式
WebVTT 的一个不太为人知和支持的功能是能够通过 CSS 扩展 为各个字幕(称为文本提示)设置样式。
::cue
伪元素是用于对各个文本轨道提示进行样式设置的目标的关键,因为它与任何定义的提示匹配。只有少数几个 CSS 属性可以应用于文本提示
color
opacity
visibility
text-decoration
text-shadow
background
简写属性outline
简写属性font
简写属性,包括line-height
white-space
例如,要更改文本轨迹提示的文本颜色,可以编写以下内容:
::cue {
color:#ccc;
}
如果 WebVTT 文件使用 语音跨度,它允许将提示定义为具有特定“语音”
0
00:00:00.000 --> 00:00:12.000
[Test]
那么这个特定的“语音”将像这样可样式化
::cue(v[voice='Test']) {
color:#fff;
background:#0095dd;
}
注意:目前,使用 ::cue 对提示进行的某些样式化在 Chrome、Opera 和 Safari 上有效,但在 Firefox 上尚不可用。
浏览器兼容性
浏览器对 WebVTT 和 <track>
元素的支持 相当好,尽管一些浏览器在实现上略有不同。
Internet Explorer
从 Internet Explorer 10+ 开始,字幕默认启用,默认控件包含一个按钮和一个菜单,提供与我们刚刚构建的菜单相同的功能。default
属性也受支持。
注意:除非设置 MIME 类型,否则 IE 将完全忽略 WebVTT 文件。这可以通过将包含 AddType text/vtt .vtt
的 .htaccess
文件添加到适当的目录来轻松完成。
Safari
Safari 6.1+ 具有与 Internet Explorer 11 相似的支持,显示一个包含不同可用选项的菜单,并添加了一个“自动”选项,允许浏览器选择。
Chrome 和 Opera
这些浏览器再次具有相似的实现:字幕默认启用,默认控件集包含一个“cc”按钮,用于打开和关闭字幕。Chrome 和 Opera 忽略 <track>
元素上的 default
属性,而是尝试将浏览器的语言与字幕的语言匹配。
Firefox
由于 错误,Firefox 的实现完全被破坏,导致 Mozilla 默认情况下关闭了 WebVTT 支持(您可以通过 media.webvtt.enabled
标志将其打开)。但是,此错误似乎已修复,并且从 Gecko 31 开始重新启用了 WebVTT 支持,因此对于 Firefox 最终发布用户来说,这将不再是一个问题(在撰写本文时,Gecko 29 存在此问题)。 从 Firefox 31 开始,此问题已修复,一切按预期工作。
插件
如果您在通读本文后,决定您不想费心去做所有这些事情,而是想让其他人为您做,那么有很多插件可以提供您可以使用的字幕和字幕支持。
- playr
- 这个小型插件实现了字幕、说明和章节,以及 WebVTT 和 SRT 文件格式。
- jwplayer
- 这款视频播放器非常强大,不仅仅支持视频字幕。它支持 WebVTT、SRT 和 DFXP 文件格式。
- MediaElement.js
- 另一个完整的视频播放器,也支持视频字幕,但仅限于 SRT 格式。
- LeanBack Player
- 另一个支持 WebVTT 字幕的视频播放器,并提供其他标准播放器功能。
- SublimeVideo
- 这款播放器还通过 WebVTT 和 SRT 文件支持字幕。
- Video.js
- 支持 WebVTT 视频字幕。
注意:您可以在 HTML5 视频播放器比较 中找到一份关于 HTML5 视频播放器及其当前状态的优秀列表。
关于 Ian Devlin
高级 Web 开发人员,就职于 pixolith。对所有 Web 相关事物感兴趣,尤其是 HTML5。爱尔兰人,但常驻德国杜塞尔多夫。
关于 Robert Nyman [资深编辑]
Mozilla Hacks 的技术布道者和编辑。发表关于 HTML5、JavaScript 和开放 Web 的演讲和博客。Robert 是 HTML5 和开放 Web 的坚定支持者,自 1999 年以来一直在从事 Web 前端开发工作,在瑞典和纽约市。他经常在 http://robertnyman.com 上发布博客,并且喜欢旅行和结识新朋友。
7 条评论