html不支持页面级懒加载,仅能通过loading="lazy"(限img/iframe)或intersectionobserver(通用精准控制)实现子资源/组件/区块的按需加载,html文件或内容区块需js+fetch动态注入。

HTML 本身不支持“页面级懒加载”——你无法让整个 index.html 按路由或滚动分块加载。所谓“页面懒加载”,实际是控制子资源(图片、iframe)、组件(Vue/React)、或内容区块(HTML 片段)的按需加载时机。核心思路就两条:用原生 loading="lazy" 快速兜底,用 IntersectionObserver 精准接管。
loading="lazy" 只对 img 和 iframe 生效,且必须带 src
这是最省事的起点,但限制极多:loading="lazy" 只在 <img> 和 <iframe></iframe> 标签上起作用,且浏览器只会在元素有 src 属性、处于主视口外、并具备明确尺寸(width/height 或 CSS aspect-ratio)时才真正延迟请求。
- 写成
<img loading="lazy">是无效的——没src,浏览器连懒加载逻辑都不会触发 -
<picture></picture>里的<source></source>加loading="lazy"会被忽略,只有最内层的<img src="...">才认这个属性 - 如果图片在
<div style="overflow-y: scroll"> 里滚动,<code>loading="lazy"基本失效,它只监听window滚动 - 首屏关键图(如 logo、Banner 第一帧)绝不能加,否则可能被延迟到用户已开始滚动才加载
- 必须调用
observer.unobserve(img),否则已加载的图片仍持续被监听,浪费资源 - 设
rootMargin: "0px 0px 200px 0px"提前触发,避免快速滚动时出现空白 - 动态插入的元素(如 AJAX 渲染后追加的
<img>),得在插入后显式调用observer.observe() - 不要在
entry.isIntersecting === true前就赋值img.src,否则可能重复加载或错失判断时机 - 服务端返回的 HTML 片段应不含
/外壳,只返回<div class="content">...</div> - 用
element.innerHTML = htmlString注入后,若需执行脚本,得用DOMParser解析并遍历<script></script>标签,再动态创建执行(仅限可信源) - 更安全的做法是改用动态
import()加载封装好的组件(如 Vue 的defineAsyncComponent或 React 的React.lazy),由构建工具拆包并管理依赖
IntersectionObserver 是唯一靠谱的手动方案
当你需要控制非 img/iframe 元素(比如自定义组件容器、广告位、长列表项),或要提前加载、处理错误、兼容老浏览器时,IntersectionObserver 是事实标准。它不卡主线程,能感知局部滚动容器,且现代浏览器全支持(Safari 12.1+ 起)。
HTML 文件或内容区块不能直接“懒加载”,得靠 JS 配合服务端
想实现“点击按钮再加载一段 HTML 内容”,HTML 本身无此能力。你必须用 fetch() 请求服务端返回的纯 HTML 字符串,再注入到 DOM。但注意:<script></script> 标签不会自动执行,<img src> 会加载,而 data-src 类属性需手动解析。
最容易被忽略的是尺寸控制:无论用哪种方案,只要图片没预设宽高或 aspect-ratio,浏览器就无法预留空间,加载时必然导致布局偏移(CLS)。这不是懒加载的问题,而是懒加载生效的前提——没占位,一切优化都白搭。











