Videospeler met eigen bediening Nieuw
Een eigen videospeler rond het gewone video-element: afspelen, tijdlijn, tijd, geluid uit en volume, ondertiteling aan of uit en volledig scherm. De bediening verdwijnt tijdens afspelen na 2,5 seconden stilstand en komt terug bij muis of focus. Sneltoetsen: spatie of k, pijltjes (5 s), m, c en f. Ondertitels komen uit een tekstspoor (hier in de JS opgebouwd, in productie een .vtt-bestand). Voor bedrijfsfilms en productvideo's waar de standaardspeler niet bij de huisstijl past.
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- Videospeler met eigen bediening · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="vsp" tabindex="-1">
<video class="vsp__v" preload="metadata" playsinline poster="https://neddev.com/lab-media/videospeler-eigen-1.webp" aria-label="Bedrijfsfilm Houtwerkplaats Van Dijk, 22 seconden"><source src="https://neddev.com/lab-media/videospeler-eigen-film.mp4" type="video/mp4"></video>
<p class="vsp__cc" hidden></p>
<button class="vsp__big" type="button" aria-label="Film afspelen"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5.5v13l10.5-6.5z"/></svg></button>
<div class="vsp__bar">
<button class="vsp__b vsp__play" type="button" aria-label="Afspelen"><svg class="vsp__ic-play" viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5.5v13l10.5-6.5z"/></svg><svg class="vsp__ic-pause" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 5h3.5v14H7zM13.5 5H17v14h-3.5z"/></svg></button>
<input class="vsp__tl" type="range" min="0" max="22" step="0.1" value="0" aria-label="Tijdlijn" aria-valuetext="0:00 van 0:22">
<span class="vsp__t"><span class="vsp__cur">0:00</span> / <span class="vsp__dur">0:22</span></span>
<button class="vsp__b vsp__mute" type="button" aria-label="Geluid uit" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9.5h3.5L12 5.5v13l-4.5-4H4z"/><path class="vsp__wave" d="M15 9c1.3 1.6 1.3 4.4 0 6M17.5 6.8c2.6 2.9 2.6 7.5 0 10.4" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path class="vsp__x" d="M15.5 9.5l5 5m0-5l-5 5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg></button>
<input class="vsp__vol" type="range" min="0" max="1" step="0.05" value="0.8" aria-label="Volume">
<button class="vsp__b vsp__ccb" type="button" aria-label="Ondertiteling" aria-pressed="false"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5.5" width="18" height="13" rx="2" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M10.5 10.3a2.2 2.2 0 1 0 0 3.4M17 10.3a2.2 2.2 0 1 0 0 3.4" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></button>
<button class="vsp__b vsp__fs" type="button" aria-label="Volledig scherm"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5" fill="none" stroke="currentColor" stroke-width="1.9"/></svg></button>
</div>
</div>
</div>/* Videospeler met eigen bediening · NedDev · eigen werk. */
.vsp{position:absolute;inset:0;background:#0a0a0a;color:#fff;font-family:'Switzer',sans-serif;container-type:inline-size;overflow:hidden;border-radius:0}
.vsp:fullscreen{width:100%;height:100%}
.vsp__v{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;background:#0a0a0a}
.vsp:fullscreen .vsp__v{object-fit:contain}
.vsp__big{position:absolute;left:50%;top:44%;width:56px;height:56px;margin:-28px 0 0 -28px;border:0;border-radius:8px;background:#F5480F;color:#fff;display:grid;place-items:center;cursor:pointer;transition:transform .2s,opacity .2s}
.vsp__big svg{width:26px;height:26px;fill:currentColor}
.vsp__big:hover{transform:scale(1.06)}
.vsp.is-started .vsp__big{opacity:0;pointer-events:none}
.vsp__bar{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;gap:6px;padding:22px 10px 8px;background:linear-gradient(to top,rgba(10,10,10,.82),rgba(10,10,10,0));transition:opacity .3s}
.vsp.is-idle .vsp__bar{opacity:0}
.vsp.is-idle{cursor:none}
.vsp__b{flex:none;width:30px;height:30px;border:0;border-radius:4px;background:transparent;color:#fff;display:grid;place-items:center;cursor:pointer;padding:0}
.vsp__b svg{width:20px;height:20px;fill:currentColor}
.vsp__b:hover{background:rgba(255,255,255,.14)}
.vsp__b:focus-visible,.vsp__big:focus-visible,.vsp__tl:focus-visible,.vsp__vol:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.vsp__ic-pause{display:none}
.vsp.is-playing .vsp__ic-play{display:none}.vsp.is-playing .vsp__ic-pause{display:block}
.vsp__x{display:none}.vsp.is-muted .vsp__x{display:block}.vsp.is-muted .vsp__wave{display:none}
.vsp__ccb[aria-pressed="true"]{color:#F5480F}
.vsp__t{flex:none;font:500 12px/1 'Switzer',sans-serif;font-variant-numeric:tabular-nums;color:#e9e7e3;white-space:nowrap}
.vsp__tl,.vsp__vol{-webkit-appearance:none;appearance:none;height:24px;margin:0;background:transparent;cursor:pointer;--p:0%}
.vsp__tl{flex:1 1 auto;min-width:40px}
.vsp__vol{flex:0 0 56px;--p:80%}
.vsp__tl::-webkit-slider-runnable-track,.vsp__vol::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:linear-gradient(to right,#F5480F var(--p),rgba(255,255,255,.3) var(--p))}
.vsp__tl::-moz-range-track,.vsp__vol::-moz-range-track{height:4px;border-radius:2px;background:linear-gradient(to right,#F5480F var(--p),rgba(255,255,255,.3) var(--p))}
.vsp__tl::-webkit-slider-thumb,.vsp__vol::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;margin-top:-4px;border-radius:50%;background:#fff;border:0}
.vsp__tl::-moz-range-thumb,.vsp__vol::-moz-range-thumb{width:12px;height:12px;border-radius:50%;background:#fff;border:0}
.vsp__cc{position:absolute;left:50%;bottom:56px;transform:translateX(-50%);width:max-content;max-width:86%;margin:0;padding:4px 8px;background:rgba(10,10,10,.8);border-radius:4px;font:500 13px/1.35 'Switzer',sans-serif;text-align:center}
.vsp.is-idle .vsp__cc{bottom:16px}
@container (max-width:370px){.vsp__vol{display:none}.vsp__bar{gap:3px;padding-left:6px;padding-right:6px}}
@media (prefers-reduced-motion:reduce){.vsp__big,.vsp__bar{transition:none}}// Videospeler met eigen bediening · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.vsp');if(!w)return;
var v=w.querySelector('.vsp__v'),big=w.querySelector('.vsp__big'),play=w.querySelector('.vsp__play'),tl=w.querySelector('.vsp__tl'),cur=w.querySelector('.vsp__cur'),dur=w.querySelector('.vsp__dur'),mute=w.querySelector('.vsp__mute'),vol=w.querySelector('.vsp__vol'),ccb=w.querySelector('.vsp__ccb'),fs=w.querySelector('.vsp__fs'),cc=w.querySelector('.vsp__cc');
function f(s){s=Math.max(0,Math.floor(s||0));return Math.floor(s/60)+':'+String(s%60).padStart(2,'0');}
var D=22;
function setP(el,frac){el.style.setProperty('--p',(Math.max(0,Math.min(1,frac))*100).toFixed(2)+'%');}
/* Ondertitels: in productie <track kind="captions" src="film.nl.vtt" srclang="nl"> */
var track=null;try{track=v.addTextTrack('captions','Nederlands','nl');[[0.3,4,'Bij Houtwerkplaats Van Dijk in Zwolle begint elke tafel als een ruwe eiken plank.'],[4.2,7.4,'Eerst schaven we het blad vlak, deels met de hand.'],[7.6,13.4,'Daarna schuren we de randen tot ze zacht aanvoelen.'],[14.4,18.8,'Drie weken later staat de tafel bij de klant, hier in Kampen.'],[19,21.8,'Benieuwd naar uw tafel? Kom langs in de werkplaats.']].forEach(function(c){track.addCue(new VTTCue(c[0],c[1],c[2]));});track.mode='hidden';
track.addEventListener('cuechange',function(){var a=track.activeCues;cc.textContent=a&&a.length?a[0].text:'';cc.hidden=!(ccb.getAttribute('aria-pressed')==='true'&&cc.textContent);});}catch(e){ccb.hidden=true;}
function sync(){var p=!v.paused&&!v.ended;w.classList.toggle('is-playing',p);play.setAttribute('aria-label',p?'Pauzeren':'Afspelen');}
function toggle(){if(v.paused||v.ended){w.classList.add('is-started');var pr=v.play();if(pr&&pr.catch)pr.catch(function(){});}else v.pause();}
big.addEventListener('click',function(){toggle();play.focus();});
play.addEventListener('click',toggle);
v.addEventListener('click',toggle);
v.addEventListener('play',sync);v.addEventListener('pause',function(){sync();show();});v.addEventListener('ended',function(){sync();show();});
v.addEventListener('loadedmetadata',function(){if(isFinite(v.duration)){D=v.duration;tl.max=D;dur.textContent=f(D);}});
v.addEventListener('timeupdate',function(){if(dragging)return;tl.value=v.currentTime;setP(tl,v.currentTime/D);cur.textContent=f(v.currentTime);tl.setAttribute('aria-valuetext',f(v.currentTime)+' van '+f(D));});
var dragging=false;
tl.addEventListener('input',function(){dragging=true;setP(tl,tl.value/D);cur.textContent=f(tl.value);v.currentTime=+tl.value;tl.setAttribute('aria-valuetext',f(tl.value)+' van '+f(D));});
tl.addEventListener('change',function(){dragging=false;});
function setVol(x){v.volume=x;v.muted=x===0;vol.value=x;setP(vol,x);upd();}
function upd(){var m=v.muted||v.volume===0;w.classList.toggle('is-muted',m);mute.setAttribute('aria-pressed',m?'true':'false');mute.setAttribute('aria-label',m?'Geluid aan':'Geluid uit');}
v.volume=.8;setP(vol,.8);
vol.addEventListener('input',function(){setVol(+vol.value);});
mute.addEventListener('click',function(){if(v.muted||v.volume===0){v.muted=false;if(v.volume===0)setVol(.6);}else v.muted=true;upd();});
ccb.addEventListener('click',function(){var on=ccb.getAttribute('aria-pressed')!=='true';ccb.setAttribute('aria-pressed',on?'true':'false');cc.hidden=!(on&&cc.textContent);});
fs.addEventListener('click',function(){if(document.fullscreenElement){document.exitFullscreen();return;}if(w.requestFullscreen)w.requestFullscreen().catch(function(){});else if(v.webkitEnterFullscreen)v.webkitEnterFullscreen();});
document.addEventListener('fullscreenchange',function(){fs.setAttribute('aria-label',document.fullscreenElement===w?'Volledig scherm sluiten':'Volledig scherm');});
var idle;function show(){w.classList.remove('is-idle');clearTimeout(idle);if(v.paused)return;idle=setTimeout(function(){var ae=document.activeElement,kb=ae&&ae!==w&&w.contains(ae)&&ae.matches(':focus-visible');if(!v.paused&&!kb)w.classList.add('is-idle');},2500);}
w.addEventListener('pointermove',show);w.addEventListener('focusin',show);v.addEventListener('play',show);
w.addEventListener('keydown',function(e){if(e.target===tl||e.target===vol){if(e.key===' '&&e.target===tl){}else return;}var k=e.key.toLowerCase();
if(k===' '||k==='k'){if(e.target.tagName==='BUTTON'&&k===' ')return;e.preventDefault();toggle();}
else if(k==='arrowright'){v.currentTime=Math.min(D,v.currentTime+5);}else if(k==='arrowleft'){v.currentTime=Math.max(0,v.currentTime-5);}
else if(k==='m'){mute.click();}else if(k==='c'){ccb.click();}else if(k==='f'){fs.click();}else return;show();});
}
init(document.querySelector('.jouw-container'));
Meer uit componenten
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →