Web'de en iyi mobil medya deneyimini nasıl oluşturursunuz? Kolay! Bu durum, kullanıcı etkileşimine ve bir web sayfasındaki medyaya verdiğiniz öneme bağlıdır. Kullanıcının ziyaretinin asıl nedeni videoysa kullanıcı deneyiminin sürükleyici ve yeniden etkileşime geçirici olması gerektiği konusunda hepimiz hemfikiriz.

Bu makalede, çok sayıda Web API'si sayesinde medya deneyiminizi nasıl aşamalı bir şekilde geliştireceğinizi ve daha etkileyici hale getireceğinizi göstereceğim. Bu nedenle, özel kontroller, tam ekran ve arka planda oynatma özellikleri sunan basit bir mobil oynatıcı deneyimi oluşturacağız. Örnek kodunu hemen deneyebilir ve kodu GitHub depomuzda bulabilirsiniz.
Özel kontroller

Gördüğünüz gibi, medya oynatıcımız için kullanacağımız HTML düzeni oldukça basit: <div>
kök öğesi, bir <video>
medya öğesi ve video kontrollerine özel bir <div>
alt öğesi içerir.
Daha sonra ele alacağımız video kontrolleri arasında oynatma/duraklatma düğmesi, tam ekran düğmesi, geri ve ileri sarma düğmeleri ve mevcut saat, süre ve zaman takibi için bazı öğeler yer alır.
<div id="videoContainer">
<video id="video" src="file.mp4"></video>
<div id="videoControls"></div>
</div>
Video meta verilerini okuma
Öncelikle, video süresini ve mevcut zamanı ayarlamak ve ilerleme çubuğunu başlatmak için video meta verilerinin yüklenmesini bekleyelim. secondsToTimeCode()
işlevinin, saniye sayısını "ss:dk:sn" biçiminde bir dizeye dönüştüren, yazdığım özel bir yardımcı program işlevi olduğunu unutmayın. Bu işlev, bizim durumumuza daha uygundur.
<div id="videoContainer">
<video id="video" src="file.mp4"></video>
<div id="videoControls">
<strong>
<div id="videoCurrentTime"></div>
<div id="videoDuration"></div>
<div id="videoProgressBar"></div>
</strong>
</div>
</div>
video.addEventListener('loadedmetadata', function () {
videoDuration.textContent = secondsToTimeCode(video.duration);
videoCurrentTime.textContent = secondsToTimeCode(video.currentTime);
videoProgressBar.style.transform = `scaleX(${
video.currentTime / video.duration
})`;
});

Videoyu oynat/duraklat
Video meta verileri yüklendikten sonra, oynatma durumuna bağlı olarak kullanıcının videoyu video.play()
ve video.pause()
ile oynatmasına ve duraklatmasına olanak tanıyan ilk düğmemizi ekleyelim.
<div id="videoContainer">
<video id="video" src="file.mp4"></video>
<div id="videoControls">
<strong><button id="playPauseButton"></button></strong>
<div id="videoCurrentTime"></div>
<div id="videoDuration"></div>
<div id="videoProgressBar"></div>
</div>
</div>
playPauseButton.addEventListener('click', function (event) {
event.stopPropagation();
if (video.paused) {
video.play();
} else {
video.pause();
}
});
Video kontrollerimizi click
etkinlik dinleyicisinde ayarlamak yerine play
ve pause
video etkinliklerini kullanırız. Kontrollerimizi etkinliğe dayalı hale getirmek esneklik sağlar (daha sonra Media Session API ile göreceğimiz gibi) ve tarayıcı oynatmaya müdahale ederse kontrollerimizi senkronize tutmamıza olanak tanır.
Video oynatılmaya başladığında düğme durumunu "duraklat" olarak değiştirir ve video kontrollerini gizleriz. Video duraklatıldığında düğme durumunu "oynat" olarak değiştirip video kontrollerini gösteririz.
video.addEventListener('play', function () {
playPauseButton.classList.add('playing');
});
video.addEventListener('pause', function () {
playPauseButton.classList.remove('playing');
});
Video currentTime
özelliği tarafından belirtilen zaman, timeupdate
video etkinliği aracılığıyla değiştiğinde, görünür durumdaysa özel denetimlerimizi de güncelleriz.
video.addEventListener('timeupdate', function () {
if (videoControls.classList.contains('visible')) {
videoCurrentTime.textContent = secondsToTimeCode(video.currentTime);
videoProgressBar.style.transform = `scaleX(${
video.currentTime / video.duration
})`;
}
});
Video sona erdiğinde düğme durumunu "oynat" olarak değiştirir, video currentTime
süresini 0 olarak ayarlayıp video kontrollerini gösteririz. Kullanıcı bir tür "otomatik oynatma" özelliğini etkinleştirdiyse başka bir videoyu otomatik olarak yüklemeyi de seçebileceğimizi unutmayın.
video.addEventListener('ended', function () {
playPauseButton.classList.remove('playing');
video.currentTime = 0;
});
Geri ve ileri sarma
Devam edip kullanıcıların bazı içerikleri kolayca atlayabilmesi için "Geri sarma" ve "İleri sarma" düğmeleri ekleyelim.
<div id="videoContainer">
<video id="video" src="file.mp4"></video>
<div id="videoControls">
<button id="playPauseButton"></button>
<strong
><button id="seekForwardButton"></button>
<button id="seekBackwardButton"></button
></strong>
<div id="videoCurrentTime"></div>
<div id="videoDuration"></div>
<div id="videoProgressBar"></div>
</div>
</div>
var skipTime = 10; // Time to skip in seconds
seekForwardButton.addEventListener('click', function (event) {
event.stopPropagation();
video.currentTime = Math.min(video.currentTime + skipTime, video.duration);
});
seekBackwardButton.addEventListener('click', function (event) {
event.stopPropagation();
video.currentTime = Math.max(video.currentTime - skipTime, 0);
});
Daha önce olduğu gibi, video stilini bu düğmelerin click
etkinlik dinleyicilerinde ayarlamak yerine, video parlaklığını ayarlamak için tetiklenen seeking
ve seeked
video etkinliklerini kullanacağız. Özel seeking
CSS sınıfım filter: brightness(0);
kadar basit.
video.addEventListener('seeking', function () {
video.classList.add('seeking');
});
video.addEventListener('seeked', function () {
video.classList.remove('seeking');
});
Şu ana kadar oluşturduklarımızı aşağıda bulabilirsiniz. Sonraki bölümde tam ekran düğmesini uygulayacağız.
Tam ekran
Burada, mükemmel ve sorunsuz bir tam ekran deneyimi oluşturmak için çeşitli Web API'lerinden yararlanacağız. Bu özelliğin işleyiş şeklini görmek için örneğe göz atın.
Elbette bunların hepsini kullanmanız gerekmez. Size uygun olanları seçip özel akışınızı oluşturmak için bunları birleştirmeniz yeterlidir.
Otomatik tam ekranı önleme
iOS'te, medya oynatmaya başlandığında video
öğeleri otomatik olarak tam ekran moduna geçer. Mobil tarayıcılarda medya deneyimimizi mümkün olduğunca özelleştirmeye ve kontrol etmeye çalışıyoruz. Bu nedenle, video
öğesinin playsinline
özelliğini iPhone'da satır içi oynatmaya zorlamak ve oynatma başladığında tam ekran moduna girmemek için ayarlamanızı öneririz. Bu işlemin diğer tarayıcılar üzerinde hiçbir yan etkisi olmadığını unutmayın.
<div id="videoContainer"></div>
<video id="video" src="file.mp4"></video><strong>playsinline</strong></video>
<div id="videoControls">...</div>
</div>
Düğme tıklandığında tam ekranı açma/kapatma
Otomatik tam ekranı önlediğimize göre, Tam Ekran API ile videonun tam ekran modunu kendimiz yönetmemiz gerekiyor. Kullanıcı "tam ekran düğmesini" tıkladığında, tam ekran modu şu anda doküman tarafından kullanılıyorsa document.exitFullscreen()
ile tam ekran modundan çıkalım. Aksi takdirde, varsa requestFullscreen()
yöntemini kullanarak video kapsayıcıda tam ekran isteğinde bulunun veya yalnızca iOS'te video öğesinde webkitEnterFullscreen()
değerini kullanın.
<div id="videoContainer">
<video id="video" src="file.mp4"></video>
<div id="videoControls">
<button id="playPauseButton"></button>
<button id="seekForwardButton"></button>
<button id="seekBackwardButton"></button>
<strong><button id="fullscreenButton"></button></strong>
<div id="videoCurrentTime"></div>
<div id="videoDuration"></div>
<div id="videoProgressBar"></div>
</div>
</div>
fullscreenButton.addEventListener('click', function (event) {
event.stopPropagation();
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
requestFullscreenVideo();
}
});
function requestFullscreenVideo() {
if (videoContainer.requestFullscreen) {
videoContainer.requestFullscreen();
} else {
video.webkitEnterFullscreen();
}
}
document.addEventListener('fullscreenchange', function () {
fullscreenButton.classList.toggle('active', document.fullscreenElement);
});
Ekran yönünü değiştirirken tam ekranı açma/kapatma
Kullanıcı cihazı yatay moda döndürdüğünde, sürükleyici bir deneyim oluşturmak için akıllıca davranıp otomatik olarak tam ekran isteğinde bulunalım. Bunun için henüz her yerde desteklenmeyen ve bazı tarayıcılarda hâlâ ön ek içeren Screen Orientation API'ye ihtiyacımız var. Bu nedenle, bu ilk aşamalı geliştirmemiz olacak.
Nasıl çalışır? Ekran yönünün değiştiğini algıladıktan sonra, tarayıcı penceresi yatay moddaysa (yani genişliği yüksekliğinden büyükse) tam ekran isteğinde bulunalım. Aksi takdirde tam ekrandan çıkalım. Hepsi bu kadar.
if ('orientation' in screen) {
screen.orientation.addEventListener('change', function () {
// Let's request fullscreen if user switches device in landscape mode.
if (screen.orientation.type.startsWith('landscape')) {
requestFullscreenVideo();
} else if (document.fullscreenElement) {
document.exitFullscreen();
}
});
}
Düğme tıklandığında ekranı yatay modda kilitle
Video yatay modda daha iyi görüntülenebildiğinden, kullanıcı "tam ekran düğmesini" tıkladığında ekranı yatay modda kilitlemek isteyebiliriz. Bu deneyimin en iyi şekilde sunulmasını sağlamak için daha önce kullanılan Screen Orientation API'yi ve bazı medya sorgularını birleştireceğiz.
Ekranı yatay olarak kilitlemek screen.orientation.lock('landscape')
aramak kadar kolaydır. Ancak bunu yalnızca cihaz matchMedia('(orientation: portrait)')
ile dikey moddayken ve matchMedia('(max-device-width: 768px)')
ile tek elle tutulabilirken yapmalıyız. Aksi takdirde tablet kullanıcıları için iyi bir deneyim olmaz.
fullscreenButton.addEventListener('click', function (event) {
event.stopPropagation();
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
requestFullscreenVideo();
<strong>lockScreenInLandscape();</strong>;
}
});
function lockScreenInLandscape() {
if (!('orientation' in screen)) {
return;
}
// Let's force landscape mode only if device is in portrait mode and can be held in one hand.
if (
matchMedia('(orientation: portrait) and (max-device-width: 768px)').matches
) {
screen.orientation.lock('landscape');
}
}
Cihaz yönünün değiştirilmesi durumunda ekranın kilidini açma
Ekran kilitliyken ekran yön değişikliklerini almadığımız için yeni oluşturduğumuz kilit ekranı deneyiminin mükemmel olmadığını fark etmiş olabilirsiniz.
Bu sorunu düzeltmek için, varsa Device Orientation API'yi kullanalım. Bu API, bir cihazın uzayda konumunu ve hareketini ölçen donanımdan bilgi sağlar: yönelimi için jiroskop ve dijital pusula, hızı için ivme ölçer. Cihazın yönünü değiştirdiğini algıladığımızda, kullanıcı cihazı dikey modda tutuyorsa ve ekran yatay modda kilitliyse ekranı screen.orientation.unlock()
ile kilitleyelim.
function lockScreenInLandscape() {
if (!('orientation' in screen)) {
return;
}
// Let's force landscape mode only if device is in portrait mode and can be held in one hand.
if (matchMedia('(orientation: portrait) and (max-device-width: 768px)').matches) {
screen.orientation.lock('landscape')
<strong>.then(function() {
listenToDeviceOrientationChanges();
})</strong>;
}
}
function listenToDeviceOrientationChanges() {
if (!('DeviceOrientationEvent' in window)) {
return;
}
var previousDeviceOrientation, currentDeviceOrientation;
window.addEventListener(
'deviceorientation',
function onDeviceOrientationChange(event) {
// event.beta represents a front to back motion of the device and
// event.gamma a left to right motion.
if (Math.abs(event.gamma) > 10 || Math.abs(event.beta) < 10) {
previousDeviceOrientation = currentDeviceOrientation;
currentDeviceOrientation = 'landscape';
return;
}
if (Math.abs(event.gamma) < 10 || Math.abs(event.beta) > 10) {
previousDeviceOrientation = currentDeviceOrientation;
// When device is rotated back to portrait, let's unlock screen orientation.
if (previousDeviceOrientation == 'landscape') {
screen.orientation.unlock();
window.removeEventListener(
'deviceorientation',
onDeviceOrientationChange,
);
}
}
},
);
}
Gördüğünüz gibi, aradığımız sorunsuz tam ekran deneyimi budur. Bu uygulamanın işleyiş şeklini görmek için örneğe göz atın.
Arka planda oynatma
Bir web sayfasının veya web sayfasındaki bir videonun artık görünmediğini tespit ettiğinizde analizlerinizi bunu yansıtacak şekilde güncelleyebilirsiniz. Bu durum, farklı bir parça seçmek, duraklatmak veya kullanıcıya özel düğmeler göstermek gibi mevcut oynatmayı da etkileyebilir.
Sayfa görünürlüğünde değişiklik olduğunda videoyu duraklatma
Sayfa Görünürlüğü API ile bir sayfanın mevcut görünürlüğünü belirleyebilir ve görünürlük değişiklikleri hakkında bildirim alabilirsiniz. Aşağıdaki kod, sayfa gizlendiğinde videoyu duraklatır. Bu durum, ekran kilidi etkinken veya sekme değiştirdiğinizde gerçekleşir.
Çoğu mobil tarayıcı artık duraklatılmış bir videonun devam ettirilmesine olanak tanıyan tarayıcı dışında kontroller sunduğundan, bu davranışı yalnızca kullanıcının arka planda oynatmaya izin verildiği durumlarda ayarlamanızı öneririz.
document.addEventListener('visibilitychange', function () {
// Pause video when page is hidden.
if (document.hidden) {
video.pause();
}
});
Video görünürlüğünde değişiklik yapıldığında sessize alma düğmesini gösterme/gizleme
Yeni Intersection Observer API'yi kullanırsanız ücretsiz olarak daha ayrıntılı analizler yapabilirsiniz. Bu API, gözlemlenen bir öğenin tarayıcı görüntü alanına ne zaman girdiğini veya görüntü alanından ne zaman çıktığını size bildirir.
Sayfadaki videonun görünürlüğüne bağlı olarak bir sessize alma düğmesi gösterelim/gizleyelim. Video oynatılıyor ancak şu anda görünmüyorsa sayfanın sağ alt köşesinde, kullanıcıya video sesi üzerinde kontrol imkanı sunan küçük bir sessize alma düğmesi gösterilir. volumechange
video etkinliği, sessize alma düğmesi stilini güncellemek için kullanılır.
<button id="muteButton"></button>
if ('IntersectionObserver' in window) {
// Show/hide mute button based on video visibility in the page.
function onIntersection(entries) {
entries.forEach(function (entry) {
muteButton.hidden = video.paused || entry.isIntersecting;
});
}
var observer = new IntersectionObserver(onIntersection);
observer.observe(video);
}
muteButton.addEventListener('click', function () {
// Mute/unmute video on button click.
video.muted = !video.muted;
});
video.addEventListener('volumechange', function () {
muteButton.classList.toggle('active', video.muted);
});
Aynı anda yalnızca bir video oynatabilirsiniz.
Bir sayfada birden fazla video varsa kullanıcının aynı anda birden fazla ses parçası duymak zorunda kalmaması için yalnızca birini oynatıp diğer videoları otomatik olarak duraklatmanızı öneririz.
// This array should be initialized once all videos have been added.
var videos = Array.from(document.querySelectorAll('video'));
videos.forEach(function (video) {
video.addEventListener('play', pauseOtherVideosPlaying);
});
function pauseOtherVideosPlaying(event) {
var videosToPause = videos.filter(function (video) {
return !video.paused && video != event.target;
});
// Pause all other videos currently playing.
videosToPause.forEach(function (video) {
video.pause();
});
}
Medya bildirimlerini özelleştirme
Media Session API ile, oynatılmakta olan videonun meta verilerini sağlayarak medya bildirimlerini de özelleştirebilirsiniz. Ayrıca, bildirimlerden veya medya tuşlarından gelebilecek sarma veya parça değiştirme gibi medyayla ilgili etkinlikleri yönetmenize olanak tanır. Bu uygulamanın bir örneğini burada bulabilirsiniz.
Web uygulamanız ses veya video oynatırken bildirim tepsisinde bir medya bildirimi görebilirsiniz. Android'de Chrome, dokümanın başlığını ve bulabileceği en büyük simge resmini kullanarak uygun bilgileri göstermek için elinden geleni yapar.
Media Session API ile başlık, sanatçı, albüm adı ve poster gibi bazı medya oturumu meta verilerini ayarlayarak bu medya bildirimini nasıl özelleştireceğinizi görelim.
playPauseButton.addEventListener('click', function(event) {
event.stopPropagation();
if (video.paused) {
video.play()
<strong>.then(function() {
setMediaSession();
});</strong>
} else {
video.pause();
}
});
function setMediaSession() {
if (!('mediaSession' in navigator)) {
return;
}
navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
artist: 'Rick Astley',
album: 'Whenever You Need Somebody',
artwork: [
{src: 'https://dummyimage.com/96x96', sizes: '96x96', type: 'image/png'},
{
src: 'https://dummyimage.com/128x128',
sizes: '128x128',
type: 'image/png',
},
{
src: 'https://dummyimage.com/192x192',
sizes: '192x192',
type: 'image/png',
},
{
src: 'https://dummyimage.com/256x256',
sizes: '256x256',
type: 'image/png',
},
{
src: 'https://dummyimage.com/384x384',
sizes: '384x384',
type: 'image/png',
},
{
src: 'https://dummyimage.com/512x512',
sizes: '512x512',
type: 'image/png',
},
],
});
}
Oynatma işlemi tamamlandığında bildirim otomatik olarak kaybolacağından medya oturumunu "bırakmanız" gerekmez. Oynatma işlemi başladığında mevcut navigator.mediaSession.metadata
değerinin kullanılacağını unutmayın. Bu nedenle, medya bildirimlerinde her zaman alakalı bilgiler göstermek için bu sayfayı güncellemeniz gerekir.
Web uygulamanızda şarkı listesi varsa kullanıcının "Önceki Parça" ve "Sonraki Parça" simgelerini kullanarak doğrudan medya bildiriminde şarkı listenizde gezinmesine izin verebilirsiniz.
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('previoustrack', function () {
// User clicked "Previous Track" media notification icon.
playPreviousVideo(); // load and play previous video
});
navigator.mediaSession.setActionHandler('nexttrack', function () {
// User clicked "Next Track" media notification icon.
playNextVideo(); // load and play next video
});
}
Medya işlem işleyicilerinin devam edeceğini unutmayın. Bu, etkinlik dinleyici kalıbına çok benzer. Tek fark, bir etkinliğin işlenmesi durumunda tarayıcının varsayılan davranışı durdurması ve bunu web uygulamanızın medya işlemini desteklediğinin bir sinyali olarak kullanmasıdır. Bu nedenle, uygun işlem işleyiciyi ayarlamadığınız sürece medya işlemi kontrolleri gösterilmez.
Bir medya işlemi işleyicisinin ayarını kaldırmak, null
değerine atama kadar kolaydır.
Media Session API, atlanan süreyi kontrol etmek istiyorsanız "Geri Sar" ve "İleri Sar" medya bildirim simgelerini göstermenize olanak tanır.
if ('mediaSession' in navigator) {
let skipTime = 10; // Time to skip in seconds
navigator.mediaSession.setActionHandler('seekbackward', function () {
// User clicked "Seek Backward" media notification icon.
video.currentTime = Math.max(video.currentTime - skipTime, 0);
});
navigator.mediaSession.setActionHandler('seekforward', function () {
// User clicked "Seek Forward" media notification icon.
video.currentTime = Math.min(video.currentTime + skipTime, video.duration);
});
}
"Oynat/Duraklat" simgesi medya bildirimde her zaman gösterilir ve ilgili etkinlikler tarayıcı tarafından otomatik olarak yönetilir. Varsayılan davranış herhangi bir nedenle işe yaramazsa "Oynat" ve "Duraklat" medya etkinliklerini yine de işleyebilirsiniz.
Media Session API'nin en iyi özelliklerinden biri, medya meta verilerinin ve denetimlerinin yalnızca bildirim tepsisinde görünmemesidir. Medya bildirimi, eşlenen tüm giyilebilir cihazlarla otomatik olarak senkronize edilir. Ayrıca kilit ekranlarında da gösterilir.