data-src是懒加载最常用的占位属性,用于存储真实图片地址,需通过javascript读取并赋值给src才能触发加载;初始src必须为空、无效或指向透明占位图,否则图片会立即加载。

data-src 是懒加载最常用的标记方式
浏览器原生不识别 data-src,但它被广泛用作“占位属性”——把真实图片地址存这里,等触发时机再赋给 src。关键不是它本身有功能,而是你用 JS 主动读取并替换。
常见错误是直接写 <img> 却没清空 src,导致图片立即加载。必须确保初始 src 为空、无效或指向 1x1 透明图:
-
src="":部分浏览器会发起空请求(如 Chrome),不推荐 -
src="data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=":稳妥的透明 GIF 占位 -
src="about:blank":在某些老环境可能出错,兼容性弱
如何用 IntersectionObserver 监听 data-src 图片
比起滚动事件监听,IntersectionObserver 更轻量、更可靠,且天然支持 data-src 的批量处理。核心逻辑是:观察元素是否进入视口 → 读取 data-src → 赋值给 src → 停止观察(避免重复加载)。
注意两个易错点:
- 必须在
observer.observe(img)前就设置好img.src = img.dataset.src,否则首次进入时可能因未赋值而加载失败 - 赋值后应立刻调用
observer.unobserve(img),否则后续滚动可能反复触发(尤其当图片高度为 0 或 CSS 隐藏时) - 如果图片有
srcset或sizes,也要同步迁移data-srcset和data-sizes
示例片段:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
if (img.dataset.srcset) img.srcset = img.dataset.srcset;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
data-src 和 loading="lazy" 能一起用吗
可以,但没必要,而且有隐藏风险。原生 loading="lazy" 已经由浏览器接管加载逻辑,此时再加 data-src 和 JS 控制,反而容易冲突。
典型问题:
- Chrome 可能先触发原生懒加载,把
src加载了,你的 JS 再去读data-src覆盖,造成重复请求 - 若图片初始
src为空,loading="lazy"可能直接跳过,导致永远不加载 - SSR 场景下,服务端无法执行 JS,
data-src不会被解析,而loading="lazy"是纯 HTML 属性,天然支持
结论:优先用 loading="lazy";仅当需兼容 Safari 15.4 以下、或要自定义加载占位、错误降级时,才用 data-src + JS 方案。
为什么 data-srcset 不能直接替换 srcset
因为 srcset 值是逗号分隔的「URL + 描述符」组合(如 "small.jpg 1x, big.jpg 2x"),而 dataset.srcset 读出来是字符串,JS 不会自动解析描述符含义。你必须原样赋值过去,不能做任何截断或拼接。
容易踩的坑:
- 误写成
img.srcset = img.dataset.srcset.split(',')[0]—— 破坏响应式逻辑 - 忘记同步
data-sizes,导致浏览器无法正确计算 DPR 下该选哪张图 - 在 WebP 支持检测后动态改
data-srcset,但没重新触发 observer,新值不会生效
安全做法:只做透传,不做解析。只要 HTML 里 data-srcset 和 data-sizes 写对了,JS 就原样搬过去。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











