De video hierboven is een voorbeeld van <mave-clip>, geïntegreerd in de UI van monumental.co.
Terwijl de productie van video ons door razendsnelle technologische ontwikkelingen blijft verbazen, zoeken we nog altijd uit hoe we die video’s het beste op het web zetten. Onlangs vroeg iemand ons of het mogelijk is het oorspronkelijke mp4-bestand uit ons systeem op te halen om in een UI te gebruiken. Dat kan, en in theorie kun je zo’n bestand rechtstreeks in je site insluiten. Toch legden we uit dat onze componenten meerdere optimalisaties combineren om je gebruikers een betere ervaring te bieden.
Daarom leggen we in dit artikel uit wat onze componenten precies doen. We beginnen met <mave-clip> (lees de documentatie) en bekijken hoe video er op het web voorstaat als het om weergave gaat — en nee, niet om het genereren ervan. We bespreken onze eigen componentenbibliotheek en implementatie, maar dezelfde principes gelden voor iedere video die je online wilt zetten.
Wat niet weet, wat niet deert. Maar zodra je dit eenmaal weet, vind je het belangrijk. Video’s zijn minder eenvoudig dan afbeeldingen, ook al zou je anders verwachten: het is toch maar een <video>-element? Er is één klein verschil: de bestandsgrootte. Dat merk je vooral wanneer je gebruikers geen snelle verbinding hebben, of onderweg in de trein op hun telefoon door je site bladeren.
Natuurlijk wil je je video in de hoogste kwaliteit aanbieden én snel laden. Dat kan. Maar meestal zijn er geen verschillende uitvoeringen beschikbaar en wordt er geen rekening gehouden met meerdere codecs. Juist die zorgen ervoor dat de video op alle apparaten en in alle browsers in de hoogst mogelijke kwaliteit afspeelt, met zo min mogelijk dataverbruik. Daar wordt het ingewikkeld.
Scott Jehl schreef op zijn site een uitstekend artikel over responsieve video — dank aan @Florisch uit onze Discord voor de tip. Zoals hij aangeeft, heeft video grote gevolgen voor prestaties, datakosten van gebruikers, hostingkosten en het totale energieverbruik. Zijn artikel is een goed vertrekpunt voor de implementatie van verschillende responsieve videobronnen. De oplossing gebruikt media queries, een CSS-techniek die sinds kort in het <video>-element door alle grote browsers wordt ondersteund. Zo eenvoudig is het:
<video>
<source src="large.mp4" media="(max-width: 1280px)" />
<source src="medium.mp4" media="(max-width: 1080px)" />
<source src="small.mp4" media="(max-width: 720px)" />
<!-- Fallback if your browser doesn't support media query in source -->
<source src="medium.mp4" />
</video>Wanneer je een video naar mave.io uploadt, maken wij die verschillende uitvoeringen voor je. Op basis van de breedte van je apparaat kunnen we zo de juiste video aanbieden. Maar er is meer.
Ook kunnen we per videoresolutie de bestandsgrootte verkleinen zonder kwaliteit in te leveren. Dat doen we met verschillende codecs. De meeste online video’s gebruiken tegenwoordig de breed ondersteunde codec h264. Met de komst van HVEC, omarmd door Apple, en AV1, omarmd door Google, hebben browsers echter meer mogelijkheden. Met een specifieke codec kan een bestand 50% of meer kleiner worden dan met h264. Dat maakt ongeacht de resolutie een nog groter verschil.
Het nadeel is dat het <video>-element dit, anders dan media queries, nog niet ondersteunt. We hebben JavaScript nodig om op basis van de browser tussen codecs te wisselen. Sommige browsers ondersteunen meerdere codecs; voor een optimale keuze verwijderen we een bron met een bepaalde codec als een andere voor die browser beter is. Dat is wat ingewikkelder, maar absoluut de moeite waard.
Hiervoor bereiden we meerdere uitvoeringen voor: verschillende formaten, ieder met meerdere codecs. Zodra die klaarstaan, gebruiken we ongeveer de volgende code om de beste bronnen te kiezen:
// We give back the codec the browser prefers
// and give h264 as fallback
function getCodecs() {
const ua = navigator.userAgent;
const isEdgeOnMac = /Edg/.test(ua) && /Mac OS/.test(ua);
const isSafari = /Safari/.test(ua) && !/Chrome/.test(ua);
const isMacOS = /Mac OS/.test(ua);
const isIOS = /iPhone|iPad/.test(ua);
if ((isMacOS && (isSafari || isEdgeOnMac)) || isIOS) {
return ["hevc", "h264"];
}
// Default to av1, h264 for all other combinations
return ["av1", "h264"];
}
function getBestSources(sources) {
return getCodecs().map((codec) =>
sources.find((source) => source.type == codec)
);
}
// Imaging giving it an array of source with
// the codecs defined and a list of multiple sizes, like:
const mySources = [
{ src: "h264.mp4", type: "h264" },
{ src: "av1.mp4", type: "av1" },
{ src: "hevc.mp4", type: "hevc" },
];
const sizes = [
{ name: "large", width: 1920 },
{ name: "medium", width: 1280 },
{ name: "small", width: 720 },
];
const bestSources = getBestSources(mySources);
// Now you can use the bestSources to create
// your video element using in multiple sizes
bestSources.forEach((source) => {
sizes.forEach((size) => {
const video = document.createElement("video");
const sourceElement = document.createElement("source");
sourceElement.src = `${size.name}_${source.src}`;
sourceElement.type = "video/mp4";
sourceElement.media = `(max-width: ${size.width}px)`;
video.appendChild(sourceElement);
document.body.appendChild(video);
});
});In combinatie met de media query kunnen we de beste video voor het apparaat en de browser van de gebruiker aanbieden. Je hoeft de code niet volledig te begrijpen. Kort gezegd controleren we welke codec de browser ondersteunt, lopen we de opgegeven bronnen met resoluties en codecs langs en genereren we het HTML-element <video> zoals hierboven.
Zoek je een eenvoudigere oplossing, gebruik dan onze component <mave-clip>. Wij regelen alles voor je: upload je video naar onze dienst en je bent klaar. Je krijgt zelfs lazy loading, zodat de video pas wordt geladen wanneer hij bijna in beeld komt.
Dat is alles. Misschien is het minder spectaculair dan gegenereerde video, maar toch: dit is behoorlijk mooi. Je hebt een responsief video-element met de beste kwaliteit en het laagst mogelijke dataverbruik.
1
2
3
4
5
<script type="module">
import { Player } from "https://cdn.video-dns.com/npm/@maveio/components/+esm";
</script>
<mave-player embed="ubg50Cq5Ilpnar1"></mave-player>
<script type="module">
import { Player } from "https://cdn.video-dns.com/npm/@maveio/components/dist/react.js";
</script>
<Player embed="ubg50Cq5Ilpnar1"></Player>
<script type="module">
import { Player } from "https://cdn.video-dns.com/npm/@maveio/components/+esm";
</script>
<mave-player embed="ubg50Cq5Ilpnar1"></mave-player>