Die Idee kam mir, als ich ein obligatorisches Schulungsvideo über Mobbing am Arbeitsplatz sah. Ich kann förmlich High School Geoff kichern hören, wie er sich über einen Weichei wie mich lustig macht, der das ansehen muss.
Aber hier sind wir.
Die Video-UI war eigentlich schön, aber es war der Fortschrittsbalken, der meine Aufmerksamkeit wirklich erregte – oder besser gesagt, der [progress].value. Es war ein einfacher Farbverlauf von Grün zu Blau, der wuchs, während das Video weiter abgespielt wurde.

Ich weiß bereits, dass es möglich ist, denselben Farbverlauf auf dem <progress>-Element zu erstellen. Pankaj Parashar hat das in einem CSS-Tricks-Post aus dem Jahr 2016 gezeigt.
Ich wollte unbedingt etwas Ähnliches nachbauen, habe mich aber noch nicht viel mit Videos beschäftigt. Ich bin auch kein Experte für JavaScript. Aber wie schwer kann das schon sein? Ich meine, alles, was ich tun will, ist herauszufinden, wie weit wir im Video sind und das zu verwenden, um den Fortschrittswert zu aktualisieren. Richtig?
Mein innerer Hänseleien hat sich so sehr über mich lustig gemacht, dass ich beschloss, es zu versuchen. Es ist nicht das Komplizierteste auf der Welt, aber ich hatte Spaß damit und wollte zeigen, wie ich es in dieser Demo eingerichtet habe.
Das Markup
Alles HTML5, Baby!
<figure>
<video id="video" src="http://html5videoformatconverter.com/data/images/happyfit2.mp4"></video>
<figcaption>
<button id="play" aria-label="Play" role="button">►</button>
<progress id="progress" max="100" value="0">Progress</progress>
</figcaption>
</figure>
Die entscheidende Zeile lautet:
<progress id="progress" max="100" value="0">Progress</progress>
Das max-Attribut sagt uns, dass wir mit 100 als höchstem Wert arbeiten, während das value-Attribut uns bei Null beginnen lässt. Das ist sinnvoll, da es uns erlaubt, den Fortschritt des Videos in Prozent zu betrachten, wobei 0% der Anfang und 100% das Ende sind, und unser anfänglicher Startpunkt 0% ist.
Styling
Ich werde definitiv nicht tief in den Prozess des Stylings des <progress>-Elements in CSS eintauchen. Der Pankaj-Post, den ich oben verlinkt habe, leistet da bereits hervorragende Arbeit. Das CSS, das wir benötigen, um einen Farbverlauf auf den Fortschrittswert zu malen, sieht so aus:
/* Fallback stuff */
progress[value] {
appearance: none; /* Needed for Safari */
border: none; /* Needed for Firefox */
color: #e52e71; /* Fallback to a solid color */
}
/* WebKit styles */
progress[value]::-webkit-progress-value {
background-image: linear-gradient(
to right,
#ff8a00, #e52e71
);
transition: width 1s linear;
}
/* Firefox styles */
progress[value]::-moz-progress-bar {
background-image: -moz-linear-gradient(
right,
#ff8a00, #e52e71
);
}
Der Trick besteht darin, auf die verschiedenen Nuancen zu achten, die es browserübergreifend kompatibel machen. Sowohl WebKit- als auch Mozilla-Browser haben ihre eigenen besonderen Wege, Fortschrittselemente zu handhaben. Das macht das Styling etwas umständlich, aber hey, was will man machen?
Den Fortschrittswert aus einem Video ermitteln
Ich wusste, dass etwas Mathematik involviert sein würde, wenn ich die aktuelle Zeit des Videos ermitteln und sie als Prozentwert anzeigen wollte. Und wenn Sie dachten, dass mir das Außenseiterdasein in der High School mathematische Superkräfte verliehen hätte, nun, sorry, ich muss Sie enttäuschen.
Ich musste eine Gliederung aufschreiben, was meiner Meinung nach passieren musste:
- Die aktuelle Zeit des Videos ermitteln. Wir müssen wissen, wo sich das Video gerade befindet, wenn wir es als Fortschrittswert anzeigen wollen.
- Die Dauer des Videos ermitteln. Die Länge des Videos zu kennen, hilft, die aktuelle Zeit als Prozent auszudrücken.
- Den Fortschrittswert berechnen. Auch hier arbeiten wir in Prozent. Mein verstaubtes Algebra-Lehrbuch sagt mir, die Formel lautet
Teil / Ganzes = % / 100. Im Kontext des Videos können wir das umformulieren zuaktuelleZeit / Dauer = Fortschrittswert.
Das gibt uns alle Anweisungen, die wir brauchen, um anzufangen. Tatsächlich können wir Variablen für die Elemente erstellen, die wir auswählen müssen, und herausfinden, mit welchen Eigenschaften wir arbeiten müssen, um die Gleichung zu füllen.
// Variables
const progress = document.getElementById( "progress" );
// Properties
// progress.value = The calculated progress value as a percent of 100
// video.currentTime = The current time of the video in seconds
// video.duration = The length of the video in seconds
Nicht schlecht, nicht schlecht. Jetzt müssen wir den Fortschrittswert berechnen, indem wir diese Dinge in unsere Gleichung einfügen.
function progressLoop() {
setInterval(function () {
document.getElementById("progress").value = Math.round(
(video.currentTime / video.duration) * 100
);
});
}
Ich gebe zu: Ich habe vergessen, dass die Gleichung zu Dezimalwerten führen würde. Dort kommt Math.round() ins Spiel, um diese auf die nächste ganze Zahl zu runden.
Das sorgt tatsächlich dafür, dass sich der Farbverlauf des Fortschrittsbalkens beim Abspielen des Videos animiert!
Ich dachte, ich könnte das als Gewinn verbuchen und glücklich weggehen. Aber es gab ein paar Dinge, die mich störten. Außerdem bekam ich Fehler in der Konsole. Kein gutes Zeichen.
Die aktuelle Zeit anzeigen
Keine große Sache, aber sicherlich eine nette Ergänzung. Wir können einen Timer neben den Fortschrittsbalken setzen und die Sekunden zählen, während wir gehen. Wir haben bereits die Daten dafür, also brauchen wir nur noch das Markup und die Verbindung.
Fassen wir die Zeit in einem <label> zusammen, da das <progress>-Element eines haben kann.
<figure>
<video controls id="video" src="http://html5videoformatconverter.com/data/images/happyfit2.mp4"></video>
<figcaption>
<label id="timer" for="progress" role="timer"></label>
<progress id="progress" max="100" value="0">Progress</progress>
</figcaption>
</figure>
Jetzt können wir es verbinden. Wir weisen ihm eine Variable zu und verwenden innerHTML, um den aktuellen Wert in das Label zu schreiben.
const progress = document.getElementById("progress");
const timer = document.getElementById( "timer" );
function progressLoop() {
setInterval(function () {
progress.value = Math.round((video.currentTime / video.duration) * 100);
timer.innerHTML = Math.round(video.currentTime) + " seconds";
});
}
progressLoop();
Hey, das funktioniert!
Extrapunkte gäbe es für die Umwandlung des Timers in das Format HH:MM:SS.
Hinzufügen eines Play-Buttons
Die Tatsache, dass gleichzeitig zwei UIs liefen, hat mich wirklich gestört. Das <video>-Element hat ein controls-Attribut, das bei Verwendung die Videosteuerung wie Play, Fortschritt, Überspringen, Lautstärke usw. anzeigt. Lassen wir das weg.
Aber das bedeutet, dass wir – mindestens – eine Möglichkeit zum Starten und Stoppen des Videos bereitstellen müssen. Lassen Sie uns das mal „button“ machen.
Fügen Sie es zuerst zum HTML hinzu
<figure>
<video id="video" src="http://html5videoformatconverter.com/data/images/happyfit2.mp4"></video>
<figcaption>
<label id="timer" for="progress" role="timer"></label>
<button id="play" aria-label="Play" role="button">►</button>
<progress id="progress" max="100" value="0">Progress</progress>
</figcaption>
</figure>
Verbinden Sie es dann mit einer Funktion, die das Video per Klick zwischen Play und Pause umschaltet.
button = document.getElementById( "play" );
function playPause() {
if ( video.paused ) {
video.play();
button.innerHTML = "❙❙";
}
else {
video.pause();
button.innerHTML = "►";
}
}
button.addEventListener( "click", playPause );
video.addEventListener("play", progressLoop);
Hey, es funktioniert immer noch!
Ich weiß, es scheint seltsam, die reichhaltigen Steuerelemente, die HTML5 direkt bietet, wegzulassen. Ich würde das wahrscheinlich nicht in einem echten Projekt tun, aber wir spielen hier nur herum.
Aufräumen meines hässlichen Spaghetti-Codes
Ich möchte meinem Kumpel Neal Fennimore wirklich danken. Er hat sich Zeit genommen, dies mit mir durchzugehen und Ratschläge zu geben, die den Code nicht nur lesbarer machen, sondern auch Zustände viel, viel besser definieren…
// States
const PAUSED = 'paused';
const PLAYING = 'playing';
// Initial state
let state = PAUSED;
…eine ordnungsgemäße Prüfung des Zustands vor dem Auslösen der Fortschrittsfunktion durchführen, während auf Play-, Pause- und Klick-Ereignisse gehört wird…
// Animation loop
function progressLoop() {
if(state === PLAYING) {
progress.value = Math.round( ( video.currentTime / video.duration ) * 100 );
timer.innerHTML = Math.round( video.currentTime ) + ' seconds';
requestAnimationFrame(progressLoop);
}
}
video.addEventListener('play', onPlay);
video.addEventListener('pause', onPause);
button.addEventListener('click', onClick);
…und sogar die Animation performanter machen, indem setInterval durch requestAnimationFrame ersetzt wird, wie Sie in diesem Ausschnitt hervorgehoben sehen können.
Hier ist es in seiner ganzen Pracht!
Oh, und ja: Ich habe daran gearbeitet, während ich das Trainingsvideo "geschaut" habe. Und ich habe das Quiz am Ende mit Bravour bestanden, vielen Dank. 🤓
Happy Feet Two?
Das scheint nicht effektiv zu sein. Warum nicht den Fortschritts-Max auf die Dauer setzen und dann die aktuelle Zeit verwenden, um den Fortschrittswert zu setzen?
Sicherlich ist es nicht merklich langsamer.
Ich scheine zu übersehen, wo
videoim JavaScript definiert ist?In einer Produktionsumgebung würden Sie das sicherlich tun, aber so zielen Sie einfach auf das HTML-Element selbst.
Gut gemacht. Wahrscheinlich würden Sie das in der Produktion so machen, aber vergessen Sie nicht,
setIntervalund die Event-Listener zu beenden, wenn das Video fertig ist.