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 zur Gestaltung eines Video-Players

Im vorherigen Artikel über einen plattformübergreifenden Video-Player haben wir beschrieben, wie man mithilfe der Media und Fullscreen APIs einen plattformübergreifenden HTML-Video-Player baut. Dieser Folgeartikel befasst sich damit, wie Sie diesen benutzerdefinierten Player gestalten können, einschließlich der Anpassung an verschiedene Bildschirmgrößen.

HTML-Markup

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

Das Markup für die benutzerdefinierten Steuerungen sieht nun wie folgt 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 zu Styling-Zwecken verwendet und diese werden mit JavaScript gesetzt. Spezifische Implementierungen werden an geeigneten Stellen unten erwähnt.

Styling

Der resultierende Videoplayer-Stil, der hier verwendet wird, ist ziemlich einfach — dies ist beabsichtigt, da das Ziel darin besteht, zu zeigen, wie ein solcher Videoplayer gestaltet und anpassungsfähig gemacht werden kann.

Hinweis: In einigen Fällen wird hier in den Codebeispielen auf einige grundlegende CSS-Elemente verzichtet, da deren Verwendung entweder offensichtlich ist oder nicht speziell für das Styling des Videoplayers relevant ist.

Grundlegendes Styling

Der Container der Videosteuerungen benötigt einige Stileinstellungen, damit er richtig eingerichtet ist:

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

Die Position wird auf relativ gesetzt, was für die Anpassungsfähigkeit 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;
}

Buttons

Die erste wesentliche Styling-Aufgabe besteht darin, die Schaltflächen der Videosteuerung so zu gestalten, dass sie wie echte Schaltflächen aussehen und funktionieren.

Jede Schaltfläche erhält einige grundlegende Stileinstellungen:

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 wird auf eine Breite und Höhe von 2rem gesetzt. Standardmäßig haben alle <button>-Elemente einen Umrandung, daher wird diese entfernt. Da Hintergrundbilder verwendet werden, um geeignete Symbole anzuzeigen, wird die Hintergrundfarbe der Schaltfläche auf transparent, nicht wiederholend und das Element sollte das Bild vollständig enthalten, eingestellt. 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 ändert:

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

Um geeignete Schaltflächenbilder zu erhalten, wurde ein Satz kostenloser, gängiger Kontrollsymbole aus dem Internet heruntergeladen. Jedes Bild wurde dann in einen Base64-codierten String konvertiert (mithilfe eines Online-Base64-Bilderkodierers), da die Bilder recht klein sind, sind die resultierenden codierten Strings recht kurz.

Da einige Schaltflächen eine doppelte Funktion haben, z.B. Spielen/Pause und Stummschalten/Stummschaltung aufheben, haben diese Schaltflächen unterschiedliche Zustände, die gestylt 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 folgende Hintergrundbilddefinitionen (die vollständigen Base64-Strings wurden aus Kürze ausgelassen):

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.

Fortschrittsleiste

Das <div>-Container des <progress>-Elements hat sein flex-grow aktiviert, sodass es den verbleibenden Raum in den Steuerelementen ausfüllt. Es zeigt auch einen Zeiger-Cursor an, um zu zeigen, dass es interaktiv ist.

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

Das <progress>-Element hat die folgenden grundlegenden Stileinstellungen:

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

Ähnlich wie die <button>-Elemente hat <progress> von Haus aus eine Umrandung, die hier entfernt wird. Es wird aus ästhetischen Gründen auch eine leichte abgerundete Ecke gegeben.

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

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

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

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

Vollbild

Nun stylen wir die Bedienelemente für den Vollbildmodus. Da das <figure>-Element dasjenige ist, das in den Vollbildmodus versetzt wird, können wir es mit der :fullscreen-Pseudoklasse ansprechen. Wir unternehmen einige Schritte:

  • Lassen Sie die figure den gesamten Bildschirm mit height: 100% einnehmen
  • Lassen Sie die Steuerleistleiste unten haften, während das Video zentriert bleibt, mithilfe von Flexbox
  • Machen Sie den Container transparent, um die native Hintergrundfarbe zu zeigen
  • Verstecken Sie die figcaption
  • Stellen Sie die Hintergrundfarbe für die Steuerungsreihe wieder her, um sicherzustellen, dass unsere schwarzen Tasten sichtbar bleiben, 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;
}

Reaktionsfähiges Styling

Da der Player nun sein grundlegendes Aussehen und Gefühl erhalten hat, sind einige weitere Stiländerungen — mit Media Queries — notwendig, um ihn anpassungsfähig zu machen.

Wir möchten das Layout der Steuerungen anpassen, wenn es auf einem kleineren Bildschirm (680px/42.5em) angezeigt wird, also wird hier ein Breakpoint definiert. Wir passen die Größen- und Positions-Eigenschaften für die Schaltflächen und die Fortschrittsleiste an, damit 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 nun über position:absolute an die Spitze des Bediensatzes verschoben, sodass er und alle Tasten breiter sein müssen. Darüber hinaus müssen die Tasten unterhalb des Fortschritt-Containers verschoben werden, damit sie sichtbar sind.

JavaScript

Das war es wirklich für das unmittelbare Styling; die nächste Aufgabe besteht darin, eine Reihe von JavaScript-Änderungen vorzunehmen, um sicherzustellen, dass alles wie erwartet funktioniert, hauptsächlich, um die Logik der Tasten zu überarbeiten.

Abspielen/Pause und Stummschaltung

Da die Tasten nun tatsächlich wie Tasten aussehen und Bilder haben, die anzeigen, was sie tun, müssen einige Änderungen vorgenommen werden, damit die "Doppelfunktion"-Tasten (wie die Wiedergabe/Pause-Taste) im richtigen "Zustand" sind und das richtige Bild anzeigen. Zu diesem Zweck wird eine neue Funktion namens changeButtonState() definiert, die eine Typvariable akzeptiert, die die Funktionalität der Taste 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 Event-Handlern 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");
});

Vielleicht haben Sie bemerkt, dass es neue Handler gibt, bei denen die play- und pause-Events auf das Video reagiert werden. Dafür gibt es einen Grund! Obwohl die Standard-Videosteuerung des Browsers deaktiviert wurde, machen viele Browser sie zugänglich, indem sie mit der rechten Maustaste auf das HTML-Video klicken. Das bedeutet, dass ein Benutzer das Video von diesen Steuerungen aus abspielen/anhalten könnte, wodurch die Tasten der benutzerdefinierten Steuerung nicht synchronisiert wären. Wenn ein Benutzer die Standardsteuerungen verwendet, werden die definierten Medien-API-Ereignisse — wie play und pause — ausgelöst, sodass dies genutzt werden kann, um sicherzustellen, dass die benutzerdefinierten Steuerungstasten synchronisiert bleiben. Unser Klick löst auch die play- und pause-Events 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 alterVolume()-Funktion, die aufgerufen wird, wenn die Lautstärketasten des Players angeklickt werden, ändert sich ebenfalls — sie ruft jetzt 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 dasselbe wie alterVolume(), aber sie setzt auch den Zustand der Stummschalttaste abhängig von der aktuellen Lautstärkeeinstellung des Videos. checkVolume() wird auch aufgerufen, wenn das volumechange-Event ausgelöst wird:

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

Fortschritt und Vollbild

Die Fortschrittsleisten- und Vollbild- Implementierungen haben sich nicht geändert.

Ergebnis

Warnung: Das Beispielvideo kann laut sein!