Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

Grundlagen der Videoplayer-Stilgestaltung

Im vorherigen Artikel Cross Browser Video Player beschrieben wir, wie ein plattformübergreifender HTML-Videoplayer unter Nutzung der Media- und Fullscreen-APIs erstellt wird. In diesem Folgeartikel geht es darum, wie dieser benutzerdefinierte Player gestaltet werden kann, inklusive seiner Responsivität.

HTML-Markup

Es wurden einige Änderungen am HTML-Markup vorgenommen, das im vorherigen Artikel gezeigt wurde. Die benutzerdefinierten Videosteuerungen und das <progress>-Element befinden sich nun innerhalb von <div>-Elementen, anstatt in ungeordneten Listenelementen.

Das Markup für die benutzerdefinierten Kontrollen sieht nun folgendermaßen aus:

html
<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>
</div>

Ein data-state-Attribut wird an verschiedenen Stellen für Stilzwecke verwendet und diese werden mithilfe von JavaScript gesetzt. Spezifische Implementierungen werden an geeigneten Stellen unten erwähnt.

Stilgestaltung

Der resultierende Videoplayer-Stil, der hier verwendet wird, ist ziemlich einfach — das ist beabsichtigt, da es darum geht zu zeigen, wie ein solcher Videoplayer gestaltet und responsiv gemacht werden kann.

Hinweis: In einigen Fällen wird hier ein grundlegendes CSS aus den Codebeispielen weggelassen, da seine Verwendung entweder offensichtlich oder nicht speziell relevant für die Gestaltung des Videoplayers ist.

Grundlegende Stilgestaltung

Der Container für die Videokontrollen benötigt einige Stilgestaltung, um korrekt eingerichtet zu sein:

css
.controls {
  display: flex;
  align-items: center;
  overflow: hidden;
  width: 100%;
  height: 2rem;
  position: relative;
}

Die Position ist auf relative gesetzt, was für die Responsivität erforderlich ist (mehr dazu später).

Wie bereits erwähnt, wird ein data-state-Attribut verwendet, um anzuzeigen, ob die Videosteuerungen sichtbar sind oder nicht, und es benötigt entsprechende CSS-Deklarationen:

css
.controls[data-state="hidden"] {
  display: none;
}

Schaltflächen

Die erste größere Stilgestaltungsaufgabe besteht darin, die Schaltflächen der Videokontrolle tatsächlich wie echte Schaltflächen aussehen und agieren zu lassen.

Jede Schaltfläche hat einige grundlegende Stilgestaltungen:

css
.controls button {
  width: 2rem;
  height: 2rem;
  text-align: center;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  border: none;
  cursor: pointer;
  color: transparent;
  background-color: transparent;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

Jede Schaltfläche hat eine Breite und Höhe von 2rem. Standardmäßig haben alle <button>-Elemente einen Rahmen, weshalb dieser entfernt wird. Da Hintergrundbilder verwendet werden, um geeignete Symbole anzuzeigen, wird die Hintergrundfarbe der Schaltfläche auf transparent, nicht wiederholt und so eingestellt, dass das Element das Bild vollständig enthält. Außerdem gibt es einige Beschriftungstexte, die nicht auf dem Bildschirm sichtbar sein sollten, daher wird die Textfarbe auf transparent gesetzt.

Die :hover- und :focus-Zustände werden dann für jede Schaltfläche festgelegt, die die Deckkraft der Schaltfläche ändern:

css
.controls button:hover,
.controls button:focus {
  opacity: 0.5;
}

Um geeignete Schaltflächenbilder zu erhalten, wurde ein Satz von kostenlosen, häufig verwendeten Steuerelement-Icons aus dem Internet heruntergeladen. Jedes Bild wurde dann in eine base64-codierte Zeichenfolge umgewandelt (mit einem Online-Base64 Image Encoder), da die Bilder ziemlich klein sind, sind die resultierenden codierten Zeichenfolgen ziemlich kurz.

Da einige Schaltflächen eine doppelte Funktionalität haben, z.B. Wiedergabe/Pause und Stummschalten/Entstummen, haben diese Schaltflächen unterschiedliche Zustände, die formatiert werden müssen. Wie bereits erwähnt, wird eine data-state-Variable verwendet, um anzuzeigen, in welchem Zustand sich solche Schaltflächen derzeit befinden.

Zum Beispiel hat die Wiedergabe/Pause-Schaltfläche die folgenden Hintergrundbilddefinitionen (die vollständigen base64-Zeichenfolgen wurden der Kürze halber weggelassen):

css
.controls button[data-state="play"] {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAA…");
}

.controls button[data-state="pause"] {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAA…");
}

Wenn der data-state der Schaltfläche geändert wird, wird auch das entsprechende Bild geändert. Alle anderen Schaltflächen werden ähnlich behandelt.

Fortschrittsbalken

Der <div>-Container für das <progress>-Element hat sein flex-grow aktiviert, sodass es den restlichen Platz in den Steuerungselementen ausfüllt. Es zeigt auch einen Zeigerzeiger an, um anzuzeigen, dass es interaktiv ist.

css
.controls .progress {
  flex-grow: 1;
  cursor: pointer;
  height: 80%;
}

Das <progress>-Element hat die folgende grundlegende Stilsetzung:

css
.controls progress {
  display: block;
  width: 100%;
  height: 100%;
  border: none;
  color: #0095dd;
  border-radius: 2px;
  margin: 0 auto;
}

Wie die <button>-Elemente hat auch <progress> einen Standardrand, der hier entfernt wird. Es erhält auch eine leicht abgerundete Ecke aus ästhetischen Gründen.

Es gibt einige browserspezifische Eigenschaften, die festgelegt werden müssen, um sicherzustellen, dass Firefox und Chrome die erforderliche Farbe für den Fortschrittsbalken verwenden:

css
.controls progress::-moz-progress-bar {
  background-color: #0095dd;
}

.controls progress::-webkit-progress-value {
  background-color: #0095dd;
}

Obwohl die gleichen Eigenschaften auf denselben Wert gesetzt sind, müssen diese Regeln separat definiert werden, oder die gesamte Deklaration könnte gültig werden, wenn ein Selektor nicht erkannt wird.

Vollbild

Jetzt formatieren wir die Kontrollen für den Vollbildmodus. Da das <figure>-Element in den Vollbildmodus gesetzt wird, können wir es mit der :fullscreen-Pseudoklasse ansprechen. Wir tun Folgendes:

  • Stellen Sie die figure auf die volle Bildschirmhöhe mit height: 100%
  • Lassen Sie die Steuerungsleiste am unteren Rand haften, während das Video zentriert bleibt, unter Verwendung von Flexbox
  • Machen Sie den Container transparent, um die native Hintergrundfarbe anzuzeigen
  • Verbergen Sie die figcaption
  • Stellen Sie die Hintergrundfarbe für die Steuerreihe wieder her, um sicherzustellen, dass unsere schwarzen Schaltflächen noch sichtbar sind, wenn der Hintergrund schwarz ist.
css
figure:fullscreen {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  max-width: 100%;
  height: 100%;
  background-color: transparent;
}
figure:fullscreen video {
  margin-top: auto;
  margin-bottom: auto;
}
figure:fullscreen figcaption {
  display: none;
}
figure:fullscreen .controls {
  background-color: #666666;
}

Responsive Stilgestaltung

Nachdem der Player seine grundlegende Optik und Haptik erhalten hat, müssen einige andere Stiländerungen – unter Verwendung von Media Queries – vorgenommen werden, um ihn responsiv zu gestalten.

Wir möchten das Layout der Steuerungen anpassen, wenn es auf einem kleineren Bildschirm (680px/42.5em) betrachtet wird, daher wird hier ein Breakpoint definiert. Wir passen die Größen- und Positionseigenschaften für die Schaltflächen und den Fortschrittsbalken so an, dass sie anders angeordnet sind:

css
@media screen and (width <= 42.5em) {
  .controls {
    height: auto;
  }

  .controls button {
    width: calc(100% / 6);
    margin-top: 2.5rem;
  }

  .controls .progress {
    position: absolute;
    top: 0;
    width: 100%;
    margin-top: 0;
    height: 2rem;
  }

  .controls .progress progress {
    width: 98%;
  }

  figcaption {
    text-align: center;
  }
}

Der .progress-Container wird jetzt über position:absolute an die Spitze des Steuerungssatzes verschoben, sodass er und alle Schaltflächen breiter sein müssen. Außerdem müssen die Schaltflächen unter den Fortschrittscontainer geschoben werden, damit sie sichtbar sind.

JavaScript

Das war wirklich alles zur unmittelbaren Stilgestaltung; die nächste Aufgabe besteht darin, eine Reihe von JavaScript-Änderungen vorzunehmen, um sicherzustellen, dass alles wie erwartet funktioniert, vor allem, um die Logik der Schaltflächen neu zu gestalten.

Wiedergabe/Pause und Stummschaltung

Da die Schaltflächen jetzt tatsächlich wie Schaltflächen aussehen und Bilder anzeigen, die deren Funktionalität anzeigen, müssen einige Änderungen vorgenommen werden, damit die "doppelte Funktionalität" der Schaltflächen (wie die Wiedergabe/Pause-Schaltfläche) im richtigen "Zustand" sind und das richtige Bild anzeigen. Um dies zu erleichtern, wird eine neue Funktion namens changeButtonState() definiert, die eine Typvariable akzeptiert, die die Funktionalität der Schaltfläche angibt:

js
function changeButtonState(type) {
  if (type === "play-pause") {
    // Play/Pause button
    if (video.paused || video.ended) {
      playPause.setAttribute("data-state", "play");
    } else {
      playPause.setAttribute("data-state", "pause");
    }
  } else if (type === "mute") {
    // Mute button
    mute.setAttribute("data-state", video.muted ? "unmute" : "mute");
  }
}

Diese Funktion wird dann von den relevanten Ereignishandlern aufgerufen:

js
video.addEventListener("play", () => {
  changeButtonState("play-pause");
});

video.addEventListener("pause", () => {
  changeButtonState("play-pause");
});

stop.addEventListener("click", (e) => {
  video.pause();
  video.currentTime = 0;
  progress.value = 0;

  // Update the play/pause button's 'data-state' which allows the
  // correct button image to be set via CSS
  changeButtonState("play-pause");
});

mute.addEventListener("click", (e) => {
  video.muted = !video.muted;
  changeButtonState("mute");
});

Sie werden bemerkt haben, dass es neue Handler gibt, wo auf die play- und pause-Ereignisse im Video reagiert wird. Dafür gibt es einen Grund! Auch wenn die standardmäßige Videosteuerung des Browsers abgeschaltet wurde, machen viele Browser sie durch einen Rechtsklick auf das HTML-Video zugänglich. Das bedeutet, dass ein Benutzer das Video über diese Steuerung abspielen/anhalten kann, was dazu führen würde, dass die Schaltflächen des benutzerdefinierten Steuerungssatzes nicht synchronisiert wären. Wenn ein Benutzer die Standardsteuerungen verwendet, werden die definierten Media-API-Ereignisse — wie play und pause — ausgelöst, sodass dies ausgenutzt werden kann, um sicherzustellen, dass die benutzerdefinierten Steuerungsschaltflächen synchronisiert bleiben. Unser Klick löst auch die play- und pause-Ereignisse aus, wenn die play()- und pause()-Methoden aufgerufen werden, sodass hier nichts geändert werden muss:

js
playPause.addEventListener("click", (e) => {
  if (video.paused || video.ended) {
    video.play();
  } else {
    video.pause();
  }
});

Lautstärke

Die Funktion alterVolume(), die aufgerufen wird, wenn die Lautstärketasten des Players geklickt werden, ändert sich ebenfalls — sie ruft nun eine neue Funktion namens checkVolume() auf:

js
function checkVolume(dir) {
  if (dir) {
    const currentVolume = Math.floor(video.volume * 10) / 10;
    if (dir === "+" && currentVolume < 1) {
      video.volume += 0.1;
    } else if (dir === "-" && currentVolume > 0) {
      video.volume -= 0.1;
    }

    // If the volume has been turned off, also set it as muted
    // Note: can only do this with the custom control set as when the 'volumechange' event is raised,
    // there is no way to know if it was via a volume or a mute change
    video.muted = currentVolume <= 0;
  }
  changeButtonState("mute");
}

function alterVolume(dir) {
  checkVolume(dir);
}
volInc.addEventListener("click", (e) => {
  alterVolume("+");
});
volDec.addEventListener("click", (e) => {
  alterVolume("-");
});

Diese neue checkVolume()-Funktion tut das Gleiche wie die alterVolume(), aber sie setzt auch den Zustand der Stummschalttaste gemäß der aktuellen Lautstärkeeinstellung des Videos. checkVolume() wird auch aufgerufen, wenn das volumechange-Ereignis ausgelöst wird:

js
video.addEventListener("volumechange", () => {
  checkVolume();
});

Fortschritt und Vollbild

Die [Fortschrittsbalken]-(/de/docs/Web/Media/Guides/Audio_and_video_delivery/cross_browser_video_player#progress) und [Vollbild]-(/de/docs/Web/Media/Guides/Audio_and_video_delivery/cross_browser_video_player#fullscreen)-Implementierungen haben sich nicht geändert.

Ergebnis

Warnung: Das Beispielvideo könnte laut sein!