loading="lazy"在Safari 15.4前、微信X5、QQ及部分企业微信/钉钉WebView中完全无效;需通过Network面板验证请求时机、Elements面板监听属性变化、检查src是否被JS覆盖或使用data-src来确认是否生效。

loading="lazy"在哪些浏览器里根本不起作用
Chrome 76+、Firefox 75+、Edge 79+ 基本可靠;Safari 直到 15.4 才开始支持,且只认 <img>,<iframe> 被忽略;iOS Safari 15.4–16.3 有滚动抖动 bug,16.4+ 修复。微信内置浏览器(X5 内核)、QQ 浏览器、部分企业微信/钉钉 WebView 完全不识别该属性——写了等于没写,也不报错。
怎么判断 loading="lazy" 实际生效了
不能只看 HTML 里有没有写,得验证行为:
- 用 Chrome DevTools Network 面板勾选 “Disable cache”,刷新后筛选
Img请求:首屏外的图不应出现在初始请求列表里 - 滚动页面,观察新请求是否随视口进入逐批出现(注意:浏览器默认提前约 1250px 加载,不是“刚好滚到才发”)
- 在 Elements 面板右键
<img>→ “Break on” → “attribute modifications”,看src是否在滚动后才被 JS 修改(如果是,说明你代码覆盖了原生逻辑) - 若
src是空或data:image/gif;base64,...占位图,而真实地址存在data-src,那原生 lazy 已失效——它只读取初始src
SSR 场景下 loading="lazy" 的坑在哪
服务端渲染时,Node 环境的 React 版本低于 16.11,loading 属性不会输出到 HTML 字符串;Vue SSR 若经 CMS 富文本过滤器处理,可能直接删掉该属性;更隐蔽的是:首屏图片若被误标为 loading="lazy",而 hydration 前 JS 还没加载,浏览器可能跳过加载,导致白屏。
- React SSR:确认服务端 React 版本 ≥ 16.11,且模板未被过滤
- Vue SSR:用
v-bind:{"loading":"lazy"}强制透传,避免编译丢失 - 首屏关键图必须显式设
loading="eager",不能依赖默认值 - 动态插入的
<img>(如分页加载),即使写了loading="lazy",也建议插入后立即检查getBoundingClientRect().top < window.innerHeight,手动触发加载
兼容性兜底必须做哪几件事
别指望一个 loading="lazy" 走天下。实际项目中,应分层处理:
立即学习“前端免费学习笔记(深入)”;
- 优先写
loading="lazy",现代浏览器零 JS 开箱即用 - 用
IntersectionObserver做降级:监听img[data-src],回调中赋值img.src = img.dataset.src并调用observer.unobserve(img) - 对
background-image、伪元素、<picture>内的<source>等非<img>场景,只能靠IntersectionObserver手动控制 - 老浏览器(如 IE11)需 fallback 到 scroll 监听 + 节流,但仅限必要场景——它会强制同步布局,慎用
真正容易被忽略的点是:loading="lazy" 和 IntersectionObserver 不是二选一,而是分层共存。前者管“能懒则懒”,后者管“必须可控”,混用时注意不要重复加载同一张图。



















