The Case for Lazy-Loading Video

Video is often the heaviest resource on a page. As with images, deferring the load of <video> elements until they are needed can yield significant performance gains. The approach you take depends on how the video is used, and whether you need to support browsers that lack the newer native lazy-loading attributes.

Native Lazy Loading With the loading Attribute

Modern browsers support the loading attribute on <video> and <audio> elements. Adding loading="lazy" defers both the media file and any poster image until the element is near the viewport. This attribute works in conjunction with, rather than as a replacement for, the preload and autoplay attributes. For instance, a video with autoplay will not start downloading until it approaches the viewport.

<video controls loading="lazy" poster="poster.jpg">
  <source src="video.mp4" type="video/mp4">
</video>

In browsers that don't yet support loading on media elements, the attribute is ignored. In that case, the poster image loads immediately, and the video loads according to the preload attribute.

Preventing Loads for Non-Autoplaying Video

When a video is not set to autoplay, the most effective way to stop the browser from fetching the file is the preload attribute. Setting preload="none" prevents any video data from loading, while the poster attribute provides a visible placeholder.

<video controls preload="none" poster="poster.jpg">
  <source src="video.mp4" type="video/mp4">
</video>

Setting preload="none" is more reliable than relying on the default metadata value. Many browsers fetch a portion of the file to locate metadata, which can inadvertently download more data than expected since the position of metadata is not always predictable. A common enhancement is to fetch the metadata when the user hovers over the video using the mouseenter event, which reduces playback delay and exposes the duration early.

<video controls preload="none" poster="poster.jpg" onmouseenter="this.preload='metadata'">
  <source src="video.mp4" type="video/mp4">
</video>

One important exception: if the video (or its poster) is an LCP candidate, it shouldn't be lazy-loaded. A poster image will load faster than the video itself, but you'll need to manage its priority manually since the fetchpriority attribute can't currently be applied to the poster attribute. Preloading the poster with a separate <link> tag and a fetchpriority="high" is a workaround.

When Video Replaces Animated GIFs

Autoplaying, looping, muted video is a common substitute for animated GIFs—and it's typically far smaller in file size. Building that behavior requires specific attributes, including playsinline for autoplay on iOS.

<video autoplay muted loop playsinline>
  <source src="video.mp4" type="video/mp4">
</video>

In supportive browsers, adding loading="lazy" is the simplest way to defer the load.

For older browsers, a JavaScript-based approach using Intersection Observer is needed. The initial markup removes autoplay and adds a class, a preload="none" attribute, and a poster image as a placeholder. The observer then re-enables autoplay when the video enters the viewport. Keeping the controls attribute offers a fallback if JavaScript fails.

JavaScript Lazy-Loading Libraries

If you cannot rely on native support or need a more managed solution, a few libraries specialize in this area. vanilla-lazyload and lozad.js are lightweight options that use Intersection Observer and may require a polyfill for older browsers. For React applications, react-lazyload provides a familiar component-based pattern, although it does not use Intersection Observer.

As native loading support for <video> extends across browsers, the need for these JavaScript-based solutions should diminish—except for cases demanding the granular control they offer.