Hinzufügen von Untertiteln und Beschriftungen zu HTML-Videos
In anderen Artikeln haben wir uns angesehen, wie man einen plattformübergreifenden Videoplayer entwickelt unter Verwendung der HTMLMediaElement und Window.fullScreen APIs, und wie man den Player stilisiert. In diesem Artikel verwenden wir denselben Player und zeigen, wie man Beschriftungen und Untertitel hinzufügt, unter Verwendung des WebVTT-Formats und des <track> Elements.
In diesem Artikel wird ein Ausschnitt aus dem Sintel Open Movie verwendet, erstellt von der Blender Foundation.
HTML und Videobeschriftungen
Bevor wir damit beginnen, wie man dem Videoplayer Beschriftungen hinzufügt, gibt es einige Dinge, die wir zuerst erwähnen werden und die Sie wissen sollten, bevor wir anfangen.
Beschriftungen versus Untertitel
Beschriftungen und Untertitel sind nicht dasselbe: Sie richten sich an verschiedene Zielgruppen und vermitteln unterschiedliche Informationen. Es wird empfohlen, sich über die Unterschiede zu informieren, wenn Sie sich nicht sicher sind, was diese sind. Sie werden jedoch technisch auf die gleiche Weise implementiert, daher gelten die Inhalte dieses Artikels für beide.
In diesem Artikel beziehen wir uns auf die angezeigten Textspuren als Untertitel, da ihr Inhalt für hörende Menschen gedacht ist, die Schwierigkeiten haben, die Sprache des Films zu verstehen, und nicht für gehörlose oder schwerhörige Menschen.
Das <track>-Element
HTML erlaubt es uns, Untertitel für ein Video mit dem <track> Element anzugeben. Die verschiedenen Attribute dieses Elements erlauben uns, Dinge wie den Typ des hinzugefügten Inhalts, die Sprache, in der er vorliegt, und natürlich eine Referenz zur Textdatei mit den tatsächlichen Untertiteldaten anzugeben.
WebVTT
Die Dateien, die die tatsächlichen Untertiteldaten enthalten, sind Textdateien, die einem vorgegebenen Format folgen, in diesem Fall das Web Video Text Tracks (WebVTT)-Format.
Videoanbieter (wie die Blender Foundation) liefern Beschriftungen und Untertitel in einem Textformat mit ihren Videos, meistens im SubRip Text (SRT)-Format. Diese können leicht mit einem Online-Konverter in WebVTT konvertiert werden.
Änderungen an HTML und CSS
Dieser Abschnitt fasst die Änderungen am Code des vorherigen Artikels zusammen, um die Hinzufügung von Untertiteln zum Video zu erleichtern. Wenn Sie daran nicht interessiert sind und direkt zu JavaScript und wichtigen CSS-Elementen gehen möchten, springen Sie zum Abschnitt Untertitel-Implementierung.
In diesem Beispiel verwenden wir ein anderes Video, Sintel, da es tatsächlich einige Sprache enthält und daher besser zur Veranschaulichung der Funktionsweise von Untertiteln geeignet ist!
HTML-Markup
Wie oben erwähnt, müssen wir das neue HTML <track>-Element verwenden, um unsere Untertiteldateien zum HTML-Video hinzuzufügen. Wir haben unsere Untertitel tatsächlich in drei verschiedenen Sprachen - Englisch, Deutsch und Spanisch - daher werden wir alle drei relevanten VTT-Dateien referenzieren, indem wir <track>-Elemente innerhalb unseres HTML <video>-Elements hinzufügen:
<video id="video" controls preload="metadata">
<source src="/shared-assets/videos/sintel-short.mp4" type="video/mp4" />
<source src="/shared-assets/videos/sintel-short.webm" type="video/webm" />
<track
label="English"
kind="subtitles"
srclang="en"
src="/shared-assets/misc/sintel-en.vtt"
default />
<track
label="Deutsch"
kind="subtitles"
srclang="de"
src="/shared-assets/misc/sintel-de.vtt" />
<track
label="Español"
kind="subtitles"
srclang="es"
src="/shared-assets/misc/sintel-es.vtt" />
</video>
Wie Sie sehen können, hat jedes <track>-Element die folgenden Attribute gesetzt:
kindist aufsubtitlesgesetzt, was den Typ des Inhalts beschreibt, den die Dateien enthalten.labelhat einen Wert, der angibt, für welche Sprache dieses Untertitelset gedacht ist - zum BeispielEnglishoderDeutsch- diese Beschriftungen erscheinen in der Benutzeroberfläche, um dem Benutzer die einfache Auswahl der gewünschten Untertitelsprache zu ermöglichen.srcist mit einer gültigen URL versehen, die auf die jeweilige WebVTT-Untertiteldatei verweist.srclanggibt an, in welcher Sprache der Inhalt jeder Untertiteldatei geschrieben ist.- Das
default-Attribut ist auf dem englischen<track>-Element gesetzt, was dem Browser anzeigt, dass dies die Standarddefinition für Untertitel ist, die verwendet werden soll, wenn Untertitel aktiviert sind und der Benutzer keine spezifische Auswahl getroffen hat.
Zusätzlich zum Hinzufügen der <track>-Elemente haben wir auch einen neuen Button hinzugefügt, um das Untertitelmenü zu steuern, das wir erstellen werden. Infolgedessen sehen die Videosteuerungen jetzt wie folgt aus:
<div id="video-controls" class="controls" data-state="hidden">
<button id="play-pause" type="button" data-state="play">Play/Pause</button>
<button id="stop" type="button" data-state="stop">Stop</button>
<div class="progress">
<progress id="progress" value="0">
<span id="progress-bar"></span>
</progress>
</div>
<button id="mute" type="button" data-state="mute">Mute/Unmute</button>
<button id="vol-inc" type="button" data-state="vol-up">Vol+</button>
<button id="vol-dec" type="button" data-state="vol-down">Vol-</button>
<button id="fs" type="button" data-state="go-fullscreen">Fullscreen</button>
<button id="subtitles" type="button" data-state="subtitles">
<span>CC</span>
</button>
</div>
CSS-Änderungen
Es gibt fast keine Änderung am CSS im Vergleich zur vorherigen Version, außer an einer Stelle, an der wir width: calc(100% / 6) durch width: calc(100% / 7) ersetzen, um Platz für den neuen Button zu schaffen. Wir setzen auch position: relative auf die Figur, damit das Untertitelmenü relativ dazu positioniert werden kann.
Für die Beschriftungsschaltfläche wird kein Bild verwendet, daher wird sie so gestylt:
.controls button[data-state="subtitles"] {
padding: 2px;
}
.controls button[data-state="subtitles"] span {
max-width: 100%;
width: 2rem;
height: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
font-weight: bold;
color: #666666;
background-color: black;
border-radius: 4px;
}
Es gibt auch andere CSS-Änderungen, die spezifisch für einige zusätzliche JavaScript-Implementierungen sind, aber diese werden an der entsprechenden Stelle unten erwähnt.
Untertitel-Implementierung
Vieles, was wir tun, um auf die Videountertitel zuzugreifen, dreht sich um JavaScript. Ähnlich wie bei den Videosteuerungen gibt es, wenn ein Browser HTML-Videountertitel unterstützt, einen Button innerhalb des nativen Steuerungssatzes, um darauf zuzugreifen. Da wir jedoch unsere eigenen Videosteuerungen definiert haben, ist dieser Button versteckt, und wir müssen unsere eigenen definieren.
Browser unterscheiden sich darin, was sie unterstützen, daher werden wir versuchen, eine einheitlichere Benutzeroberfläche für jeden Browser zu schaffen, wo immer möglich. Mehr zu Problemen mit der Browser-Kompatibilität weiter unten.
Initiales Setup
Wie bei allen anderen Schaltflächen müssen wir eine der ersten Dinge tun, und zwar einen Zugriff auf die Untertitel-Schaltfläche speichern:
const subtitles = document.getElementById("subtitles");
Wir schalten auch zunächst alle Untertitel aus, falls der Browser einige davon standardmäßig einschaltet:
for (const track of video.textTracks) {
track.mode = "hidden";
}
Die Eigenschaft video.textTracks enthält ein Array aller Textspuren, die dem Video angehängt sind. Wir durchlaufen jede von ihnen und setzen ihren mode auf hidden.
Hinweis: Die WebVTT API gibt uns Zugriff auf alle Textspuren, die für ein HTML-Video mit dem <track>-Element definiert sind.
Erstellen eines Beschriftungsmenüs
Unser Ziel ist es, die zuvor hinzugefügte subtitles-Schaltfläche zu nutzen, um ein Menü anzuzeigen, das es den Benutzern ermöglicht, auszuwählen, in welcher Sprache die Untertitel angezeigt werden sollen, oder sie vollständig auszuschalten.
Wir haben die Schaltfläche hinzugefügt, aber bevor wir sie funktionsfähig machen, müssen wir das damit verbundene Menü erstellen. Dieses Menü wird dynamisch erstellt, sodass Sprachen später hinzugefügt oder entfernt werden können, indem die <track>-Elemente im Markup des Videos bearbeitet werden.
Alles, was wir tun müssen, ist, die textTracks des Videos durchzugehen, ihre Eigenschaften auszulesen und das Menü entsprechend aufzubauen:
const subtitleMenuButtons = [];
let subtitlesMenu;
if (video.textTracks) {
const df = document.createDocumentFragment();
subtitlesMenu = df.appendChild(document.createElement("ul"));
subtitlesMenu.className = "subtitles-menu";
subtitlesMenu.appendChild(createMenuItem("subtitles-off", "", "Off"));
for (const track of video.textTracks) {
subtitlesMenu.appendChild(
createMenuItem(
`subtitles-${track.language}`,
track.language,
track.label,
),
);
}
videoContainer.appendChild(subtitlesMenu);
}
Dieser Code erstellt ein documentFragment, das verwendet wird, um eine ungeordnete Liste zu halten, die unser Untertitelmenü enthält. Zunächst wird eine Option hinzugefügt, um alle Untertitel auszuschalten, und dann werden Schaltflächen für jede Textspur hinzugefügt, wobei die Sprache und das Label von jedem ausgelesen werden.
Das Erstellen jedes Listenpunkts und der Schaltfläche erfolgt durch die createMenuItem() Funktion, die wie folgt definiert ist:
function createMenuItem(id, lang, label) {
const listItem = document.createElement("li");
const 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", (e) => {
// Set all buttons to inactive
subtitleMenuButtons.forEach((button) => {
button.setAttribute("data-state", "inactive");
});
// Find the language to activate
const lang = button.getAttribute("lang");
for (const track of video.textTracks) {
// For the 'subtitles-off' button, the first condition will never match so all will subtitles be turned off
if (track.language === lang) {
track.mode = "showing";
button.setAttribute("data-state", "active");
} else {
track.mode = "hidden";
}
}
subtitlesMenu.style.display = "none";
});
subtitleMenuButtons.push(button);
return listItem;
}
Diese Funktion erstellt die erforderlichen <li> und <button> Elemente und gibt sie zurück, damit sie zur Untertitelliste hinzugefügt werden können. Sie richtet auch die erforderlichen Event-Listener auf der Schaltfläche ein, um die betreffende Untertitelgruppe ein- oder auszuschalten. Dies geschieht durch Setzen des mode-Attributs der erforderlichen Untertitel auf showing und der anderen auf hidden.
Sobald das Menü erstellt ist, wird es dann am unteren Ende des videoContainer in den DOM eingefügt.
Anfänglich ist das Menü standardmäßig verborgen, daher muss ein Event-Listener auf unsere Untertitelschaltfläche hinzugefügt werden, um es umzuschalten:
subtitles.addEventListener("click", (e) => {
if (subtitlesMenu) {
subtitlesMenu.style.display =
subtitlesMenu.style.display === "block" ? "none" : "block";
}
});
CSS des Untertitelmenüs
Wir haben auch einige grundlegende Stile für das neu erstellte Untertitelmenü hinzugefügt:
.subtitles-menu {
display: none;
position: absolute;
bottom: 3rem;
right: 0;
background: #666666;
list-style-type: none;
margin: 0;
width: 100px;
padding: 10px;
}
.subtitles-menu li {
padding: 0;
text-align: center;
}
.subtitles-menu li button {
border: none;
background: black;
color: white;
cursor: pointer;
width: 90%;
padding: 2px 5px;
border-radius: 2px;
}
Styling der angezeigten Untertitel
Eine der weniger bekannten und unterstützten Funktionen von WebVTT ist die Möglichkeit, die einzelnen Untertitel (sogenannte Textcues) über CSS zu gestalten.
Das ::cue Pseudo-Element ist der Schlüssel, um einzelne Text-Track-Cues für das Styling zu bestimmen, da es auf jeden definierten Cue passt. Es gibt nur eine Handvoll CSS-Eigenschaften, die auf einen Textcue angewendet werden können:
coloropacityvisibilitytext-decorationtext-shadowbackgroundKurzschreibweiseoutlineKurzschreibweisefontKurzschreibweise, einschließlichline-heightwhite-space
Beispielsweise können Sie die Textfarbe der Text-Track-Cues ändern, indem Sie Folgendes schreiben:
::cue {
color: #cccccc;
}
Wenn die WebVTT-Datei voice spans verwendet, die es ermöglichen, Cues als eine bestimmte "Stimme" zu definieren:
0 00:00:00.000 --> 00:00:12.000 <v Test>[Test]</v>
Dann kann diese bestimmte 'Stimme' wie folgt gestylt werden:
::cue(v[voice="Test"]) {
color: white;
background: #0095dd;
}