v147 · HTML

Compatibility Lab

Detects whether loading="lazy" works on <video> and <audio> elements via DOM attribute reflection. Runs a live probe injecting a video element with loading="lazy" and checking whether the attribute is reflected. Provides the IntersectionObserver fallback pattern for browsers without native media lazy loading.

API probes

Live attribute reflection test

video.loading — attribute reflection check
Click "Run probe" to test…

invalid value contract

The media loading property is an enumerated attribute. Unknown values are preserved in markup but the IDL property falls back to eager, matching the feature conformance suite.

video invalid value not run
audio invalid value not run
Click "Try invalid values" to verify the fallback.

Native vs JS fallback comparison

Native CHROME 147+
Set the attribute and done:
<video loading="lazy" src="…">

Browser chooses threshold automatically based on connection speed and scroll velocity. Zero JavaScript. Works with prerender. Respects prefers-reduced-data.
JS Fallback ALL BROWSERS
Use IntersectionObserver:
<video data-src="…">
Observe → set src on entry.

Works everywhere but requires JavaScript, a custom threshold, and careful observer cleanup.
Detecting which approach to use in this browser…

Fallback pattern

/* Detect native lazy loading on media elements */ const VIDEO_LAZY = (() => { const v = document.createElement('video'); return 'loading' in v; })(); const AUDIO_LAZY = (() => { const a = document.createElement('audio'); return 'loading' in a; })(); /* Apply lazy loading — native or IntersectionObserver */ function lazyLoad(el) { if (VIDEO_LAZY && (el.tagName === 'VIDEO' || el.tagName === 'AUDIO')) { el.loading = 'lazy'; if (el.dataset.src) { el.src = el.dataset.src; delete el.dataset.src; } return; } // Fallback: IntersectionObserver el.src = ''; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const target = entry.target; target.src = target.dataset.src; observer.unobserve(target); } }); }, { rootMargin: '200px' }); // 200px buffer like Chrome's native threshold observer.observe(el); } /* Usage */ document.querySelectorAll('video[data-src], audio[data-src]').forEach(lazyLoad);

references

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗