Medya öğeleri (<video> ve <audio>) ve bunlarla ilişkili kaynaklar (ör. <video poster> resimler ve önceden yüklenmiş meta veriler), ilk sayfa yüklemesi sırasında önemli miktarda ağ ve depolama bant genişliği tüketir. <video> üzerinde preload="metadata" veya preload="none" ayarlanmış olsa bile tarayıcı, poster resmini hemen getirir ve preload="metadata", sayfadaki her oynatıcıda medya başlıkları için aralık istekleri başlatmaya devam eder.
Ekran dışı <video> ve <audio> öğelerine loading="lazy" eklemek, tarayıcıya poster resim indirmeleri, preload ipuçları ve autoplay yürütme dahil olmak üzere tüm medya ağı isteklerini, öğe görsel görüntü alanından tarayıcı tarafından hesaplanan bir mesafeye ulaşana kadar ertelemesini söyler.
Nasıl uygulanır?
- Ekran dışı medyaya
loading="lazy"ekleyin: Ekranın alt kısmında yer alan<video>ve<audio>öğelerineloading="lazy"uygulayın. Ekranın üst kısmındaki medyadaloadingözelliğini atlayarak varsayılan olarakeagerdeğerini almasını sağlayın. <video>öğelerinde açıkçawidthveheightdeğerleri ayarlayın:<video>öğelerinde her zaman tam sayıwidthveheightözelliklerini (CSS pikseli cinsinden) belirtin. Yüklenmeyen videolar varsayılan olarak300×150boyutlarındadır. Açıkça boyutlandırma yapılmazsa geç yüklenen bir video, görünür görüntü alanıyla kesişmeyebilir ve hiç yüklenmeyebilir ya da yüklendiğinde rahatsız edici düzen kaymalarına (CLS) neden olabilir.<audio>öğelerinecontrolsözelliğini ekleyin:<audio loading="lazy">öğelerine her zamancontrolsözelliğini ekleyin.<audio>öğelerinin tarayıcı kontrolleri olmadan içsel görsel kutusu olmadığından,controlsiçermeyen bir<audio loading="lazy">öğesi görüntü alanıyla görünür şekilde kesişemez ve hiçbir zaman yüklenmez veya otomatik olarak oynatılmaz.- Koordinat
preloadveposterözellikleri:<video loading="lazy">üzerinde, hemposterresim getirme hem depreloaddavranışı (none,metadataveyaauto), video görüntüleme alanına yaklaşana kadar ertelenir.- Kullanıcının medyaya kaydırdıktan sonra oynat düğmesine açıkça basması gerektiğinde
loading="lazy"ilepreload="none", oynatıcı görüntü alanına girdiğinde süre ve ilk kare verilerinin otomatik olarak doldurulması gerektiğinde isepreload="metadata"eşleyin.
- Yavaş yüklemeyi
autoplaygüvenli bir şekilde işleme:loading="lazy", sesi kapatılmış bir<video>(veya etkinleştirilmiş bir<audio controls>) üzerindeautoplayile birleştirildiğinde, oynatma ve indirme işlemleri öğe görüntü alanına yaklaşana kadar bekler. Hareketli medyayı otomatik olarak oynatmadan önce her zaman@media (prefers-reduced-motion: reduce)ayarına uyun.
Örnek kod
<!-- Above-the-fold hero video: DO NOT use loading="lazy".
Omit loading (defaults to "eager") so the poster and initial media load immediately. -->
<video
controls
width="1280"
height="720"
poster="/images/hero-poster.jpg"
preload="metadata"
>
<source src="/media/keynote.webm" type="video/webm">
<source src="/media/keynote.mp4" type="video/mp4">
<track src="/media/keynote-en.vtt" kind="captions" srclang="en" label="English">
</video>
<!-- Below-the-fold video player:
MANDATORY: Specify integer width and height attributes so the unloaded video
has a non-zero layout box to intersect the viewport and avoids layout shift.
Both the poster image and preload="metadata" are deferred until near the viewport. -->
<video
controls
loading="lazy"
width="800"
height="450"
poster="/images/tutorial-poster.jpg"
preload="metadata"
>
<source src="/media/tutorial.webm" type="video/webm">
<source src="/media/tutorial.mp4" type="video/mp4">
<track src="/media/tutorial-en.vtt" kind="captions" srclang="en" label="English">
</video>
<!-- Below-the-fold inline product loop:
With loading="lazy" and autoplay, downloading and playback wait until the
video approaches the viewport. Include muted and playsinline for autoplay. -->
<video
controls
loading="lazy"
autoplay
loop
muted
playsinline
width="640"
height="360"
poster="/images/feature-loop-poster.jpg"
>
<source src="/media/feature-loop.webm" type="video/webm">
<source src="/media/feature-loop.mp4" type="video/mp4">
<track src="/media/feature-loop-en.vtt" kind="captions" srclang="en" label="English">
</video>
<!-- Below-the-fold audio player:
MANDATORY: Include the controls attribute. Lazy-loaded <audio> without
controls is invisible, cannot intersect the viewport, and will never load. -->
<figure>
<figcaption id="episode-title">Episode 42: Browser Architecture Deep Dive</figcaption>
<audio
controls
loading="lazy"
preload="metadata"
src="/media/episode-42.mp3"
aria-labelledby="episode-title"
aria-details="episode-transcript"
></audio>
<details id="episode-transcript">
<summary>View transcript</summary>
<p>Transcript content for Episode 42...</p>
</details>
</figure>
// Pause autoplaying videos when the user prefers reduced motion
const reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
function syncReducedMotion(prefersReducedMotion) {
for (const video of document.querySelectorAll('video[autoplay]')) {
if (prefersReducedMotion) {
video.removeAttribute('autoplay');
video.pause();
}
}
}
syncReducedMotion(reducedMotionQuery.matches);
reducedMotionQuery.addEventListener('change', (event) => {
syncReducedMotion(event.matches);
});
En iyi uygulamalar
- ZORUNLU:
<video>öğelerinde her zaman açıkwidthveheightözelliklerini ayarlayın. Yüklenmemiş videoların iç boyutu300×150olur ve sayfanın görünür bir bölümüyle kesişmezlerse hiçbir zaman yüklenmezler. - ZORUNLU:
<audio loading="lazy">öğelerine her zamancontrolsözelliğini ekleyin.controlsiçermeyen geç yüklenen<audio>öğeleri görünür şekilde oluşturulmaz ve hiçbir zaman yüklenmez veya otomatik olarak oynatılmaz. posterresim ve video verilerinin getirilmesini geciktirdiğinden, ekranın üst kısmındaki veya Largest Contentful Paint (LCP)<video>öğelerineloading="lazy"UYGULAMAYIN.loading="eager"değerini açıkça yazmak yerine varsayılan istekli yükleme tercih edildiğindeloadingözelliğini atlayın.- Geç yüklenen
<video>veya<audio>öğelerinin ne zaman yüklendiğini algılamak içinwindowloadetkinliğine GÜVENMEYİN.loadetkinliği,loading="lazy"medya öğesi başlangıçta görsel görüntü alanının içinde olsa bile yalnızca istekli yüklenen medyaya göre tetiklenir. - UNUTMAYIN: Tarayıcılar,
loading="lazy"medyasını yalnızca JavaScript etkinleştirildiğinde erteler (komut dosyası oluşturma devre dışı bırakıldığında sunucuların medya istekleri aracılığıyla kaydırma konumunu tahmin etmesini önlemek için izleme önleme önlemi).
Yedek strateji
Baseline hedefiniz <video> ve <audio> üzerinde loading="lazy" desteklemiyorsa bant genişliğinin ne kadar sıkı bir şekilde korunması gerektiğine bağlı olarak progresif geliştirme ile IntersectionObserver yedek arasında seçim yapın:
Progresif geliştirme (önerilen varsayılan)
<video> ve <audio> öğelerinde loading="lazy" özelliğini tanımayan tarayıcılar bu özelliği yoksayar ve preload özelliği tarafından yönetilen standart yüklemeye geri döner. loading="lazy" ile preload="none" veya preload="metadata" eşleştirildiğinde, desteklenmeyen tarayıcıların medya dosyasının tamamını önceden indirmesi engellenir. Ancak <video poster> resimler ve preload="metadata" başlıklar istekli olarak getirilir.
Özel kod yedeklemesi (IntersectionObserver)
Baseline hedefiniz, yerel destek sunmayan tarayıcılarda <video poster> indirmelerini, preload="metadata" isteklerini veya görüntü alanıyla tetiklenen oynatmayı kesin olarak ertelemeyi gerektirdiğinde Object.hasOwn(HTMLMediaElement.prototype, 'loading') özelliğini algılayın ve ardından IntersectionObserver özelliğine geri dönün:
// Feature-detect native media lazy loading on HTMLMediaElement.prototype
const supportsLazyMedia = Object.hasOwn(HTMLMediaElement.prototype, 'loading');
if (!supportsLazyMedia) {
const lazyMediaElements = document.querySelectorAll(
'video[loading="lazy"], audio[loading="lazy"][controls]',
);
// Example-only rootMargin value; adjust distance threshold for your layout
const mediaObserver = new IntersectionObserver(
(entries, observer) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
const media = entry.target;
// Restore deferred poster and preload attributes when entering the viewport
if (media.dataset.poster) {
media.poster = media.dataset.poster;
delete media.dataset.poster;
}
if (media.dataset.preload) {
media.preload = media.dataset.preload;
delete media.dataset.preload;
}
if (media.dataset.src) {
media.src = media.dataset.src;
delete media.dataset.src;
}
for (const source of media.querySelectorAll('source[data-src]')) {
source.src = source.dataset.src;
delete source.dataset.src;
}
media.load();
observer.unobserve(media);
}
},
{ rootMargin: '200px 0px' },
);
for (const media of lazyMediaElements) {
// Hold back network fetches in unsupported browsers until intersection
if (media.hasAttribute('poster')) {
media.dataset.poster = media.getAttribute('poster');
media.removeAttribute('poster');
}
if (media.hasAttribute('preload') && media.getAttribute('preload') !== 'none') {
media.dataset.preload = media.getAttribute('preload');
}
media.preload = 'none';
mediaObserver.observe(media);
}
}