v148 · HTML · loading="lazy"

Performance Compare

Old approach: 18 lines of JavaScript per video (IntersectionObserver setup, src swap, load call, observer disconnect). New approach: one HTML attribute. Same result.

loading="lazy" is supported in Chrome 148+, Edge 148+. The attribute is ignored gracefully in other browsers (all videos load eagerly) — no broken experience, just no savings.

Before — IntersectionObserver

Above fold — hero text, nav
fold
video 1 — below fold
video 2 — far below fold
video 3 — far below fold
JS code required 18 lines/video
initial data loaded 0 KB
observer instances 0

Chrome 148 — loading="lazy"

Above fold — hero text, nav
fold
video 1 — loading="lazy"
video 2 — loading="lazy"
video 3 — loading="lazy"
JS code required 0 lines
initial data loaded 0 KB
observer instances 0 (browser handles)

Code comparison

Before — 18 lines per video

const videos = document.querySelectorAll(
  'video[data-src]'
);

const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach(entry => {
      if (!entry.isIntersecting) return;
      const video = entry.target;
      video.src = video.dataset.src;
      video.load();
      observer.unobserve(video);
    });
  },
  { rootMargin: '200px' }
);

videos.forEach(v => observer.observe(v));
▲ 18 lines + data-src plumbing in HTML

Chrome 148 — 1 attribute

<!-- HTML only: -->
<video
  src="clip.mp4"
  loading="lazy"
  poster="thumb.jpg"
  controls
></video>

<!-- That's it. No JS. -->
<!-- Browser applies optimal threshold
     based on connection speed,
     device memory, and scroll speed. -->
▲ 1 attribute, 0 JavaScript

see also

implementation reference

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