মিডিয়া এলিমেন্ট (<video> এবং <audio>) এবং তাদের সাথে সম্পর্কিত রিসোর্স (যেমন <video poster> ছবি এবং আগে থেকে লোড করা মেটাডেটা) প্রাথমিক পৃষ্ঠা লোড করার সময় উল্লেখযোগ্য নেটওয়ার্ক এবং স্টোরেজ ব্যান্ডউইথ ব্যবহার করে। এমনকি যখন preload="metadata" বা preload="none" কোনও <video>-এ সেট করা থাকে, তখন ব্রাউজার অবিলম্বে তার poster ছবি নিয়ে আসে এবং preload="metadata" এখনও পৃষ্ঠার প্রতিটি প্লেয়ার জুড়ে মিডিয়া হেডারের জন্য রেঞ্জ অনুরোধ শুরু করে।
অফস্ক্রিন <video> এবং <audio> এলিমেন্টে loading="lazy" যোগ করলে, ব্রাউজারকে সমস্ত মিডিয়া নেটওয়ার্ক অনুরোধ স্থগিত করার নির্দেশ দেয়—যার মধ্যে poster ছবি ডাউনলোড, preload ইঙ্গিত এবং autoplay এক্সিকিউশন অন্তর্ভুক্ত—যতক্ষণ না এলিমেন্টটি ভিজ্যুয়াল ভিউপোর্ট থেকে ব্রাউজার-গণনা করা দূরত্বে পৌঁছায়।
কীভাবে প্রয়োগ করতে হয়
- অফস্ক্রিন মিডিয়াতে
loading="lazy"যোগ করুন: ফোল্ডের নিচে থাকা<video>ও<audio>এলিমেন্টেloading="lazy"প্রয়োগ করুন। অ্যাবাভ-দ্য-ফোল্ড মিডিয়াতেloadingঅ্যাট্রিবিউট বাদ দিন যাতে এটি ডিফল্ট হিসেবেeager-এ সেট হয়ে যায়। <video>এলিমেন্টে স্পষ্টwidthএবংheightসেট করুন:<video>-এ সবসময় পূর্ণসংখ্যাwidthএবংheightঅ্যাট্রিবিউট (CSS পিক্সেলে) উল্লেখ করুন। আনলোড করা ভিডিও ডিফল্ট হিসেবে300×150ডাইমেনশনে থাকে; নির্দিষ্ট সাইজ না থাকলে, ধীরে ধীরে লোড করা ভিডিও দৃশ্যমান ভিউপোর্টের সাথে ইন্টারসেক্ট করতে পারে না এবং কখনও লোড হয় না অথবা লোড হওয়ার সময় লেআউট শিফ্ট (CLS) সংক্রান্ত সমস্যা তৈরি করে।<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ম্যানেজ করা: মিউট করা<video>(বা অপ্ট-ইন<audio controls>)-এloading="lazy"-এর সাথে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>এলিমেন্ট দৃশ্যমানভাবে রেন্ডার করা হয় না এবং কখনই লোড বা অটোপ্লে হবে না। loading="lazy"অ্যাট্রিবিউটটি 'অ্যাবাভ-দ্য-ফোল্ড' বা Largest Contentful Paint (LCP)<video>এলিমেন্টে প্রয়োগ করবেন না, কারণ এটিposterছবি ও ভিডিও ডেটা ফেচ করতে দেরি করে।- স্পষ্টভাবে
loading="eager"লেখার পরিবর্তে ডিফল্ট ইগার লোডিং বাঞ্ছনীয় হলেloadingঅ্যাট্রিবিউট বাদ দিন। - ধীরে ধীরে লোড হওয়া
<video>বা<audio>এলিমেন্ট কখন লোড হয়েছে তা শনাক্ত করার জন্যwindowloadইভেন্টের উপর নির্ভর করবেন না।loadইভেন্ট শুধুমাত্র ইগার-লোডেড মিডিয়ার উপর ভিত্তি করে ফায়ার করে, এমনকিloading="lazy"মিডিয়া এলিমেন্ট প্রাথমিকভাবে ভিজ্যুয়াল ভিউপোর্টের মধ্যে থাকলেও। - মনে রাখবেন যে জাভাস্ক্রিপ্ট চালু থাকলে তবেই ব্রাউজার
loading="lazy"মিডিয়া ডিফার করে (স্ক্রিপ্টিং বন্ধ থাকলে মিডিয়া অনুরোধের মাধ্যমে সার্ভার যাতে স্ক্রল পজিশন অনুমান করতে না পারে তার জন্য অ্যান্টি-ট্র্যাকিং ব্যবস্থা)।
ফলব্যাক স্ট্র্যাটেজি
আপনার বেসলাইন টার্গেট যদি <video> এবং <audio>-এ loading="lazy" সাপোর্ট না করে, তাহলে ব্যান্ডউইথ কতটা কঠোরভাবে সংরক্ষণ করতে হবে তার উপর ভিত্তি করে প্রোগ্রেসিভ এনহ্যান্সমেন্ট এবং IntersectionObserver ফলব্যাকের মধ্যে বেছে নিন:
প্রোগ্রেসিভ এনহ্যান্সমেন্ট (সাজেস্ট করা ডিফল্ট)
যেসব ব্রাউজার <video> ও <audio>-এ loading="lazy" শনাক্ত করতে পারে না, সেগুলি অ্যাট্রিবিউট উপেক্ষা করে এবং preload অ্যাট্রিবিউট দ্বারা পরিচালিত স্ট্যান্ডার্ড লোডিংয়ে ফিরে যায়। preload="none" বা preload="metadata"-এর সাথে loading="lazy" পেয়ার করলে, কাজ করে না এমন ব্রাউজারও সম্পূর্ণ মিডিয়া ফাইল ডাউনলোড করা এড়িয়ে যেতে পারে, যদিও <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);
}
}