मीडिया एलिमेंट (<video> और <audio>) और उनसे जुड़े संसाधन (जैसे, <video poster> इमेज और पहले से लोड किया गया मेटाडेटा), पेज लोड के शुरुआती दौरान काफ़ी नेटवर्क और स्टोरेज बैंडविथ का इस्तेमाल करते हैं. <video> पर preload="metadata" या preload="none" सेट होने पर भी, ब्राउज़र तुरंत उसकी poster इमेज फ़ेच करता है. साथ ही, preload="metadata" अब भी पेज पर मौजूद हर प्लेयर के मीडिया हेडर के लिए, रेंज के अनुरोध शुरू करता है.
ऑफ़स्क्रीन <video> और <audio> एलिमेंट में loading="lazy" जोड़ने से, ब्राउज़र को सभी मीडिया नेटवर्क अनुरोधों को रोकने का निर्देश मिलता है. इनमें poster इमेज डाउनलोड, preload हिंट, और autoplay एक्ज़ीक्यूशन शामिल हैं. ऐसा तब तक होता है, जब तक एलिमेंट, विज़ुअल व्यूपोर्ट से ब्राउज़र के हिसाब से तय की गई दूरी तक नहीं पहुंच जाता.
इन्हें कैसे लागू करें
- ऑफ़स्क्रीन मीडिया में
loading="lazy"जोड़ें: वेबसाइट में फ़ोल्ड के नीचे मौजूद<video>और<audio>एलिमेंट परloading="lazy"लागू करें. पेज के ऊपरी हिस्से में मौजूद मीडिया परloadingएट्रिब्यूट का इस्तेमाल न करें, ताकि वह डिफ़ॉल्ट रूप सेeagerपर सेट हो जाए. <video>एलिमेंट परwidthऔरheightको साफ़ तौर पर सेट करें:<video>पर हमेशा पूर्णांकwidthऔरheightएट्रिब्यूट (सीएसएस पिक्सल में) की जानकारी दें. अनलोड किए गए वीडियो, डिफ़ॉल्ट रूप से300×150डाइमेंशन पर सेट होते हैं. अगर वीडियो का साइज़ साफ़ तौर पर नहीं बताया गया है, तो हो सकता है कि लेज़ी-लोड किया गया वीडियो, दिखने वाले व्यूपोर्ट को इंटरसेक्ट न कर पाए और कभी लोड न हो. इसके अलावा, लोड होने पर लेआउट शिफ़्ट (सीएलएस) में रुकावट आ सकती है.<audio>एलिमेंट मेंcontrolsएट्रिब्यूट शामिल करें:<audio loading="lazy">में हमेशाcontrolsशामिल करें.<audio>एलिमेंट में ब्राउज़र कंट्रोल के बिना कोई विज़ुअल बॉक्स नहीं होता. इसलिए,controlsके बिना<audio loading="lazy">एलिमेंट, व्यूपोर्ट को विज़ुअल तौर पर इंटरसेक्ट नहीं कर सकता. साथ ही, यह कभी लोड नहीं होगा या अपने-आप नहीं चलेगा.preloadऔरposterएट्रिब्यूट को कोऑर्डिनेट करना:<video loading="lazy">पर,posterइमेज फ़ेच औरpreloadव्यवहार (none,metadataयाauto), दोनों को तब तक के लिए रोक दिया जाता है, जब तक वीडियो व्यूपोर्ट के पास नहीं पहुंच जाता.loading="lazy"कोpreload="none"के साथ तब जोड़ें, जब उपयोगकर्ता को मीडिया पर स्क्रोल करने के बाद, 'चलाएं' बटन को साफ़ तौर पर दबाना पड़े. इसके अलावा,preload="metadata"को तब जोड़ें, जब प्लेयर के व्यूपोर्ट में आने के बाद, अवधि और शुरुआती फ़्रेम का डेटा अपने-आप भर जाए.
- लेज़ी
autoplayको सुरक्षित तरीके से हैंडल करना: जबloading="lazy"को म्यूट किए गए<video>(या ऑप्ट-इन<audio controls>) परautoplayके साथ जोड़ा जाता है, तो वीडियो तब तक नहीं चलता और डाउनलोड नहीं होता, जब तक कि एलिमेंट व्यूपोर्ट के पास नहीं पहुंच जाता. मोशन मीडिया को अपने-आप चलाने से पहले, हमेशा@media (prefers-reduced-motion: reduce)का पालन करें.
कोड का उदाहरण
<!-- 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);
});
सबसे सही तरीके
- ज़रूरी:
<video>एलिमेंट पर,widthऔरheightएट्रिब्यूट की वैल्यू हमेशा साफ़ तौर पर सेट करें. लोड न होने वाले वीडियो का साइज़300×150होता है. अगर वे पेज के दिखने वाले हिस्से को इंटरसेक्ट नहीं करते हैं, तो वे कभी लोड नहीं होंगे. - ज़रूरी:
<audio loading="lazy">एलिमेंट में हमेशाcontrolsएट्रिब्यूट शामिल करें.controlsके बिना लेज़ी-लोड किए गए<audio>एलिमेंट, साफ़ तौर पर रेंडर नहीं होते. साथ ही, वे कभी लोड नहीं होंगे या अपने-आप नहीं चलेंगे. - पेज के सबसे ऊपर दिखने वाले हिस्से या सबसे बड़े एलिमेंट को रेंडर करने में लगने वाले समय (एलसीपी)
<video>से जुड़े एलिमेंट परloading="lazy"लागू न करें. ऐसा करने से,posterइमेज और वीडियो, दोनों का डेटा फ़ेच होने में देरी होती है. - ज़रूर करें: अगर आपको
loading="eager"को साफ़ तौर पर लिखने के बजाय, डिफ़ॉल्ट ईगर लोडिंग का इस्तेमाल करना है, तोloadingएट्रिब्यूट को हटा दें. <video>या<audio>एलिमेंट के लोड होने का पता लगाने के लिए,windowloadइवेंट पर भरोसा न करें.loadइवेंट सिर्फ़ ईगर-लोड किए गए मीडिया के आधार पर ट्रिगर होता है. भले ही,loading="lazy"मीडिया एलिमेंट शुरुआत में विज़ुअल व्यूपोर्ट में मौजूद हो.- ध्यान दें कि ब्राउज़र,
loading="lazy"मीडिया को सिर्फ़ तब रोकते हैं, जब JavaScript चालू हो. यह ट्रैकिंग रोकने का एक तरीका है. इससे सर्वर, स्क्रिप्टिंग बंद होने पर मीडिया अनुरोधों के ज़रिए स्क्रोल की पोज़िशन का अनुमान नहीं लगा पाते.
फ़ॉलबैक रणनीति
अगर आपका बेसलाइन टारगेट, <video> और <audio> पर loading="lazy" के साथ काम नहीं करता है, तो प्रोग्रेसिव एन्हांसमेंट और IntersectionObserver फ़ॉलबैक में से कोई एक चुनें. यह इस बात पर निर्भर करता है कि बैंडविड्थ को कितनी सख्ती से सुरक्षित रखना है:
परतदार वृद्धि (सुझाया गया डिफ़ॉल्ट)
<video> और <audio> पर loading="lazy" को न पहचानने वाले ब्राउज़र, एट्रिब्यूट को अनदेखा कर देते हैं. साथ ही, preload एट्रिब्यूट से नियंत्रित स्टैंडर्ड लोडिंग पर वापस चले जाते हैं. loading="lazy" को preload="none" या preload="metadata" के साथ जोड़ने से यह पक्का होता है कि काम न करने वाले ब्राउज़र, पूरी मीडिया फ़ाइल को पहले से डाउनलोड न करें. हालांकि, <video poster> इमेज और preload="metadata" हेडर को तुरंत फ़ेच किया जाएगा.
कस्टम कोड फ़ॉलबैक (IntersectionObserver)
जब आपके बेसलाइन टारगेट के लिए, <video poster> डाउनलोड, preload="metadata" अनुरोधों या नेटिव सपोर्ट के बिना ब्राउज़र में व्यूपोर्ट से ट्रिगर होने वाले प्लेबैक को पूरी तरह से टालना ज़रूरी हो, तो सुविधा का पता लगाएं Object.hasOwn(HTMLMediaElement.prototype, 'loading'), फिर IntersectionObserver पर वापस जाएं:
// 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);
}
}