عناصر رسانه (<video> و <audio>) و منابع مرتبط با آنها (مانند تصاویر <video poster> و فرادادههای پیشبارگذاریشده) درطول بارگیری اولیه صفحه، پهنای باند شبکه و فضای ذخیرهسازی قابلتوجهی را مصرف میکنند. حتی وقتی preload="metadata" یا preload="none" روی <video> تنظیم شده باشد، مرورگر مشتاقانه تصویر poster آن را فوراً واکشی میکند و preload="metadata" همچنان درخواستهای محدوده را برای سرایندهای رسانه در همه پخشکنندههای صفحه آغاز میکند.
افزودن loading="lazy" به عناصر <video> و <audio> خارج از صفحه به مرورگر دستور میدهد تا همه درخواستهای شبکه رسانه را بهتعویق بیندازد—ازجمله بارگیریهای تصویر poster، نکات preload، و اجرای autoplay—تا زمانی که عنصر به فاصله محاسبهشده توسط مرورگر از نمای دیداری برسد.
نحوه پیادهسازی
- افزودن
loading="lazy"به رسانه خارج از صفحه:loading="lazy"را به عناصر<video>و<audio>که در زیر خط تا قرار دارند اعمال کنید. مشخصهloadingرا در رسانه بالای خط تا حذف کنید تا بهطور پیشفرض بهeagerتبدیل شود. - تنظیم صریح
widthوheightدر عناصر<video>: همیشه مشخصههای عدد صحیحwidthوheight(در پیکسلهای CSS) را در<video>مشخص کنید. ویدیوهای بارنشده بهطور پیشفرض ابعاد300×150دارند؛ بدون اندازهگذاری صریح، ممکن است ویدیو بارشده بهصورت کُند نتواند با نمای دیدنی تقاطع داشته باشد و هرگز بار نشود، یا هنگام بار شدن باعث تغییرات چیدمان مختلکننده (CLS) شود. - مشخصه
controlsرا در عناصر<audio>اضافه کنید: همیشهcontrolsرا در<audio loading="lazy">اضافه کنید. چون عناصر<audio>بدون کنترلهای مرورگر جعبه دیداری ذاتی ندارند، عنصر<audio loading="lazy">بدونcontrolsنمیتواند بهطور قابلمشاهده با نمای هدف تلاقی داشته باشد و هرگز بار نمیشود یا بهطور خودکار پخش نمیشود. - مشخصههای
preloadوposterمختصات:- در
<video loading="lazy">، هم واکشی تصویرposterو هم رفتارpreload(none،metadata، یاauto) تا زمانی که ویدیو به نمای هدف نزدیک شود بهتعویق میافتد. - وقتی کاربر باید پساز پیمایش به رسانه صریحاً روی پخش فشار دهد،
loading="lazy"را باpreload="none"جفت کنید، یا وقتی مدت و دادههای فریم اولیه باید بهطور خودکار پساز ورود پخشکننده به نمای هدف پر شود،loading="lazy"را باpreload="metadata"جفت کنید.
- در
- مدیریت ایمن بارگیری تنبل
autoplay: وقتیloading="lazy"باautoplayدر<video>بیصدا (یا<audio controls>موافقتشده) ترکیب میشود، بازپخش و بارگیری تا زمانی که عنصر به نمای دید نزدیک شود منتظر میمانند. همیشه قبلاز پخش خودکار رسانه حرکتی،@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);
});
روالهای مطلوب
- اجباری: همیشه مشخصههای صریح
widthوheightرا روی عناصر<video>تنظیم کنید. ویدیوهای بارنشده اندازه ذاتی300×150دارند و اگر با بخش قابلمشاهده صفحه تلاقی نداشته باشند هرگز بار نخواهند شد. - اجباری: همیشه مشخصه
controlsرا در عناصر<audio loading="lazy">اضافه کنید. عناصر<audio>بارشده بهصورت کُند بدونcontrolsبهصورت نمایان رندر نمیشوند و هرگز بار نمیشوند یا بهطور خودکار پخش نمیشوند. loading="lazy"را برای عناصر بالای خط تا یا «بزرگترین نقاشی دارای محتوا» (LCP)<video>اعمال نکنید، زیرا واکشی دادههایposterتصویر و ویدیو را بهتأخیر میاندازد.- باید مشخصه
loadingرا زمانی که بارگیری مشتاقانه پیشفرض مدنظر است حذف کنید، بهجای اینکه صریحاًloading="eager"را بنویسید. - برای تشخیص زمان بار شدن عناصر
<video>یا<audio>بارشده بهصورت کُند، به رویدادwindowloadاتکا نکنید. رویدادloadفقط براساس رسانه بارشده مشتاقانه فعال میشود، حتی اگر عنصر رسانهloading="lazy"در ابتدا داخل نمای دیداری باشد. - توجه داشته باشید که مرورگرها فقط زمانی رسانه
loading="lazy"را بهتعویق میاندازند که JavaScript فعال باشد (یک اقدام ضد ردیابی برای جلوگیری از استنباط موقعیت پیمایش توسط سرورها ازطریق درخواستهای رسانه زمانی که اسکریپتنویسی غیرفعال است).
راهبرد جایگزین
اگر هدف «خط پایه» شما از loading="lazy" در <video> و <audio> پشتیبانی نمیکند، براساس اینکه پهنای باند چقدر باید بهطور دقیق حفظ شود، بین ارتقای پیشرو و بازگشت IntersectionObserver یکی را انتخاب کنید:
ارتقای پیشرو (پیشفرض توصیهشده)
مرورگرهایی که loading="lazy" را در <video> و <audio> تشخیص نمیدهند، این مشخصه را نادیده میگیرند و به بارگیری استاندارد که توسط مشخصه preload کنترل میشود برمیگردند. جفت کردن loading="lazy" با preload="none" یا preload="metadata" تضمین میکند که مرورگرهای پشتیبانینشده همچنان از بارگیری کامل فایل رسانه در ابتدا اجتناب کنند، هرچند تصاویر <video poster> و سرایندهای preload="metadata" با اشتیاق واکشی خواهند شد.
جایگزین کد سفارشی (IntersectionObserver)
وقتی هدف Baseline شما بهطور دقیق مستلزم بهتعویق انداختن بارگیریهای <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);
}
}