Web 平台 API / iframe 的尺寸 · 让内容决定高度 / iframe 的懒加载与占位 待审核 3 / 4
loading="lazy" · 2500px

iframe 的懒加载与占位

一个嵌入了视频播放器、地图或评论组件的 iframe,加载的不只是一个文档,而是一整套脚本、样式与网络请求。一篇文章末尾的评论 iframe,读者可能根本不会滚到那里,它却和首屏内容同时开始下载。loading="lazy" 对 iframe 的意义比对图片更大。

1 · 与图片共用的定义

HTML 规范的 lazy loading attribute 一节同时服务于 <img> 与 <iframe>:lazy 推迟加载直到元素接近视口,eager 是缺省值,脚本禁用时不懒加载(反追踪),推迟的机制都是文档的 lazy load intersection observer。这些规则在 响应式图片 · loading 一页有展开,本页只看 iframe 不同的地方。

iframe 的 loading 属性在 Chrome 77(2019-09)与图片同时落地,Safari 16.4(2023-03)、Firefox 121(2023-12)随后支持(兼容性据 MDN BCD,核对于 2026-09),比图片的懒加载晚了一到四年。

2 · 另一组提前量

规范只说提前量是 implementation-defined,没有要求 iframe 与图片相同。实测 Chrome 154(桌面、视口 1280 × 900)在同一页面里的读数:(核对于 2026-09)

元素 纵向提前量 横向提前量
<img loading="lazy"> 1250px 625px
<iframe loading="lazy"> 2500px 2500px

另开一个全新的浏览器上下文、视口宽 1440px 时复测,iframe 仍是纵向 2500px(顶边位于 3390px 的加载、3400px 的不加载)、横向 2500px(左边位于 3930px 的加载、3940px 的不加载)(核对于 2026-09)。

两处差别都说得通。iframe 加载要走一整轮文档请求、解析与脚本执行,比一张图片慢得多,提前量加倍是为了让它在滚到之前就绪。横向不减半则更可能是实现上的选择:图片的横向提前量减半,大概是考虑到横向轮播里的大量图片;iframe 很少成排横向排列,Chrome 没有为它单独设这一档。后一条是作者的推测,没有找到公开的说明。

图 2-1 · 嵌套滚动容器中 40 个等距的懒加载元素,记录各自开始加载时距可视边缘的距离。可在 iframe 与 img 之间切换,观察两者纵横两个方向上的提前量。

3 · 不懒加载的 iframe

有三类 iframe 在 Chrome 154 里无视 loading="lazy":srcdoc 生成的、src 为 blob: URL 的、src 为 about:blank 的。实测把它们放在距视口 9000px 处,三者都在一秒内完成加载,contentDocument 里已有内容;同样位置的 http 地址 iframe 保持 about:blank,直到滚近才加载(核对于 2026-09)。

规范的 process the iframe attributes 算法对 srcdoc 与 src 两个分支都写了懒加载:srcdoc 分支同样先检查 will lazy load element steps,满足时推迟到相交再导航到 about:srcdoc。blob: 走 src 分支,按规范也应当懒加载;只有 about:blank 在首次插入时直接触发 load、不发起导航,立即加载是规范行为。前两类的立即加载是 Chrome 与规范文本的差异,看上去它只对 http(s) 地址启用懒加载(核对于 2026-09)。本系列其他页的 lab 都用 srcdoc,唯独图 2-1 必须指向一个真实的 http 地址,原因即在此。

与之相对,隐藏的 iframe 会被正常懒加载。实测 9000px 处的 display: none、visibility: hidden、0 × 0 与 4 × 4 的 iframe 都没有加载。

4 · 懒加载与按内容定高

按内容定高的 iframe 在加载前是默认的 150px(或外层给的初始高度),加载后跳到内容高度,这次跳变推开下方所有内容(见 双向同意 §4)。两个特性叠在一起时,跳变发生的时刻由懒加载决定:iframe 距视口还有约 2500px 时就开始加载,内容高度确定时它通常仍在屏幕之外。

按 Layout Instability API 的定义,只有位移前后在视口内可见的元素才计入 CLS。视口之外的 iframe 变高、把它下方同样在视口之外的内容推下去,读者看不到,CLS 也不记录。首屏里的 iframe 则相反,它的跳变全程可见;这类 iframe 不应懒加载,而且最好由外层给一个接近实际内容的初始高度,缩小跳变幅度。代价见 requestResize() §2:初始高度同时决定了锁定的视口,也就成为 iframe 高度的下限。

建议 · 首屏以下的嵌入组件同时写 loading="lazy" 与 frame-sizing: content-height。懒加载 2500px 的提前量足以把按内容定高的跳变移出视口,两个特性互相补足:一个省下首屏带宽,一个消除内部滚动条。