如何为HTML5 <video>元素实现类似img的loading="lazy"懒加载效果?
解决方案
完全可以实现和img loading="lazy"效果一致的视频懒加载,同时解决首帧显示的问题,以下是两种落地路径:
方案1:原生属性实现(最简方案)
目前主流浏览器(Chrome 77+、Firefox 75+、Edge 79+)已经原生支持video标签的loading="lazy"属性,用法和图片懒加载完全一致,搭配poster属性指定首帧即可解决preload="none"无首帧的问题:
<video src="your-video.mp4" controls loading="lazy" poster="video-first-frame.webp" width="600" height="400" ></video>
注:首帧可以提前用FFmpeg批量导出为WebP格式,单张体积通常只有十几KB,远低于视频元数据请求的开销
方案2:JS兼容实现(兼容旧浏览器)
如果需要覆盖更低版本的浏览器,可以用IntersectionObserver实现自定义懒加载,从根源上避免初始状态的206请求。
之前用preload="none"还是会产生请求的原因是,只要video标签设置了src属性,浏览器默认就会发起请求拉取视频元数据,所以才会产生大量206请求,把src放到自定义属性里初始不赋值,就能彻底避免这个问题:
步骤1:HTML结构调整
不要在初始状态给video设置src属性,把真实视频地址存在自定义属性data-src中,poster属性照常设置首帧:
<video class="lazy-video" controls preload="none" data-src="your-video.mp4" poster="video-first-frame.webp" width="600" height="400" ></video>
步骤2:JS懒加载逻辑
用IntersectionObserver监听元素可见性,视频进入视口前200px时再动态赋值src触发加载:
const lazyVideoObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const targetVideo = entry.target // 赋值真实视频地址触发加载 targetVideo.src = targetVideo.dataset.src // 加载完成后取消监听避免重复触发 lazyVideoObserver.unobserve(targetVideo) } }) }, { // 提前200px预加载,避免滚动到可视区后等待 rootMargin: '200px 0px', threshold: 0.1 }) // 绑定所有需要懒加载的视频 document.querySelectorAll('.lazy-video').forEach(video => { lazyVideoObserver.observe(video) })
这个方案初始状态不会发起任何视频相关的HTTP请求,完全消除了不必要的206请求,且IntersectionObserver由浏览器原生优化,不会造成滚动卡顿。
内容的提问来源于stack exchange,提问作者jokoon
相关产品推荐
相关产品推荐

