Hinzufügen von Untertiteln und Kaptionen zu HTML-Videos
In anderen Artikeln haben wir uns angesehen, wie man einen plattformübergreifenden Video-Player baut unter Verwendung der HTMLMediaElement und Window.fullScreen APIs, sowie wie man den Player gestaltet. Dieser Artikel übernimmt denselben Player und zeigt, wie man ihm Untertitel und Kaptionen hinzufügt, unter Verwendung des WebVTT-Formats und des <track> Elements.
In diesem Artikel nutzt unser Beispiel einen Auszug aus dem Sintel-Open-Movie, erstellt von der Blender Foundation.
HTML und Videountertitel
Bevor wir darauf eingehen, wie Untertitel zum Video-Player hinzugefügt werden, gibt es ein paar Dinge, die wir zuerst erwähnen sollten und die Sie wissen sollten, bevor wir starten.
Kaptionen versus Untertitel
Kaptionen und Untertitel sind nicht dasselbe: Sie haben erheblich unterschiedliche Zielgruppen und vermitteln verschiedene Informationen. Es wird empfohlen, sich über die Unterschiede zu informieren, wenn Sie sich nicht sicher sind, was sie bedeuten. Sie werden jedoch technisch auf gleiche Weise implementiert, weshalb der Inhalt dieses Artikels auf beide zutrifft.
Für diesen Artikel werden wir uns auf die als Untertitel angezeigten Textspuren beziehen, da ihr Inhalt für hörende Personen gedacht ist, die Schwierigkeiten haben, die Sprache des Films zu verstehen, anstatt für gehörlose oder schwerhörige Personen.
Das <track> Element
HTML ermöglicht es uns, Untertitel für ein Video mit dem <track> Element anzugeben. Die verschiedenen Attribute dieses Elements erlauben es uns, Dinge wie die Art des Inhalts, den wir hinzufügen, die Sprache und natürlich einen Verweis auf die Textdatei, die die eigentlichen Untertiteldaten enthält, zu spezifizieren.
WebVTT
Die Dateien, die die eigentlichen Untertiteldaten enthalten, sind Textdateien, die einem vorgegebenen Format folgen, in diesem Fall dem Web Video Text Tracks (WebVTT) Format.
Videoproduzenten (wie die Blender Foundation) stellen Kaptionen und Untertitel in einem Textformat mit ihren Videos zur Verfügung, aber sie liegen normalerweise im SubRip Text (SRT) Format vor. Diese können leicht mit einem Online-Converter in WebVTT umgewandelt werden.
Änderungen an HTML und CSS
Dieser Abschnitt fasst die Änderungen zusammen, die am Code des vorherigen Artikels vorgenommen wurden, um das Hinzufügen von Untertiteln zum Video zu erleichtern. Wenn Sie daran nicht interessiert sind und direkt zum JavaScript und relevanterem CSS springen möchten, überspringen Sie zum Abschnitt Untertitelimplementierung.
In diesem Beispiel verwenden wir ein anderes Video, Sintel, da es tatsächlich Sprachpassagen enthält und daher besser geeignet ist, um zu veranschaulichen, wie Untertitel funktionieren!
HTML-Markup
Wie oben erwähnt, müssen wir das neue HTML <track> Element verwenden, um unsere Untertiteldateien dem HTML-Video hinzuzufügen. Tatsächlich haben wir unsere Untertitel in drei verschiedenen Sprachen — Englisch, Deutsch und Spanisch — daher werden wir alle drei entsprechenden 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:
kindhat den Wertsubtitles, was die Art des Inhalts angibt, den die Dateien enthalten.labelhat einen Wert, der angibt, für welche Sprache dieses Untertitelset ist — zum BeispielEnglishoderDeutsch— diese Labels erscheinen in der Benutzeroberfläche, sodass der Benutzer leicht auswählen kann, welche Untertitelsprache er sehen möchte.srcwird eine gültige URL zugewiesen, die auf die relevante WebVTT-Untertiteldatei in jedem Fall verweist.srclanggibt an, in welcher Sprache der Inhalt jeder Untertiteldatei ist.- Das
defaultAttribut ist am englischen<track>Element gesetzt, was dem Browser anzeigt, dass dies die Standard-Untertiteldateidefinition ist, die verwendet werden soll, wenn Untertitel eingeschaltet sind und der Benutzer keine spezifische Auswahl getroffen hat.
Zusätzlich zu den <track> Elementen haben wir auch eine neue Schaltfläche 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 im CSS von der vorherigen Version, außer einer Stelle, an der wir width: calc(100% / 6) mit width: calc(100% / 7) ersetzen, um die neue Schaltfläche zu berücksichtigen. Wir setzen auch position: relative auf die Figur, sodass das Untertitelmenü-Aufklappfenster relativ dazu positioniert werden kann.
Für die Untertitel-Schaltfläche wird kein Bild verwendet, daher wird sie folgendermaßen gestaltet:
.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 unten an der entsprechenden Stelle erwähnt.
Untertitelimplementierung
Vieles von dem, was wir tun, um auf die Videountertitel zuzugreifen, dreht sich um JavaScript. Ähnlich wie bei den Videosteuerungen, wenn ein Browser HTML-Videountertitel unterstützt, wird ein Button innerhalb des nativen Steuerungssatzes bereitgestellt, um auf sie zuzugreifen. Da wir jedoch unsere eigenen Videosteuerungen definiert haben, ist dieser Button verborgen, und wir müssen unseren eigenen definieren.
Browser unterscheiden sich darin, was sie unterstützen, daher werden wir versuchen, jedem Browser, wo möglich, eine einheitlichere Benutzeroberfläche zu bieten. Mehr zu Browserkompatibilitätsproblemen kommt später.
Erste Einrichtung
Wie bei allen anderen Schaltflächen müssen wir eine Referenz auf die Untertitel-Schaltfläche speichern:
const subtitles = document.getElementById("subtitles");
Wir schalten auch zunächst alle Untertitel aus, falls der Browser einige von ihnen standardmäßig einschaltet:
for (const track of video.textTracks) {
track.mode = "hidden";
}
Die video.textTracks Eigenschaft enthält ein Array aller Textspuren, die dem Video angehängt sind. Wir durchlaufen jede einzelne und setzen ihren mode auf hidden.
Anmerkung: Die WebVTT API gibt uns Zugriff auf alle Textspuren, die für ein HTML-Video unter Verwendung des <track> Elements definiert sind.
Erstellen eines Kapitonenmenüs
Unser Ziel ist es, die hinzugefügte subtitles-Schaltfläche zu verwenden, um ein Menü anzuzeigen, das es den Benutzern erlaubt, auszuwählen, in welcher Sprache sie die Untertitel angezeigt bekommen möchten, oder sie vollständig auszuschalten.
Wir haben die Schaltfläche hinzugefügt, aber bevor wir sie etwas tun lassen, müssen wir das Menü erstellen, das dazu gehört. 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, deren Eigenschaften auszulesen und das Menü daraus 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. Zuerst wird eine Option hinzugefügt, die es dem Benutzer ermöglicht, alle Untertitel auszuschalten, und dann werden Schaltflächen für jede Textspur hinzugefügt, wobei die Sprache und das Label von jeder gelesen werden.
Das Erstellen jedes Listenpunkts und jeder 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, sodass sie zur Liste des Untertitelmenüs hinzugefügt werden können. Sie richtet auch die erforderlichen Ereignis-Listener auf der Schaltfläche ein, um das betreffende Untertitelset ein- oder auszuschalten. Dies wird erreicht, indem das mode Attribut des erforderlichen Untertitels auf showing gesetzt und das der anderen auf hidden gesetzt wird.
Sobald das Menü erstellt ist, wird es am unteren Rand des videoContainer in den DOM eingefügt.
Initial ist das Menü standardmäßig ausgeblendet, daher muss ein Ereignis-Listener zu unserer Untertitel-Schaltfläche hinzugefügt werden, um es umzuschalten:
subtitles.addEventListener("click", (e) => {
if (subtitlesMenu) {
subtitlesMenu.style.display =
subtitlesMenu.style.display === "block" ? "none" : "block";
}
});
CSS für das Untertitelmenü
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;
}
Gestaltung der angezeigten Untertitel
Eine der weniger bekannten und unterstützten Funktionen von WebVTT ist die Fähigkeit, die individuellen Untertitel (sogenannte Textmarkierungen) über CSS zu gestalten.
Das ::cue Pseudoelement ist der Schlüssel, um individuelle Textspur-Cues zu gestalten, da es zu jedem definierten Cue passt. Es gibt nur eine Handvoll von CSS-Eigenschaften, die auf einen Text-Cue angewendet werden können:
coloropacityvisibilitytext-decorationtext-shadowbackgroundKurzform-EigenschaftenoutlineKurzform-EigenschaftenfontKurzform-Eigenschaften, einschließlichline-heightwhite-space
Um zum Beispiel die Textfarbe der Textspur-Cues zu ändern, können Sie schreiben:
::cue {
color: #cccccc;
}
Wenn die WebVTT-Datei Sprachabschnitte 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 wird diese spezifische 'Stimme' folgendermaßen stilisierbar sein:
::cue(v[voice="Test"]) {
color: white;
background: #0095dd;
}