症状
劣化随一个属性而来,服务出的 HTML 直接可见:hero 图上挂着 loading=“lazy”。性能面板显示后果:LCP 标记在脚本与低优先级资源之后才触发——lazy 提示把图片移出了早期加载管线。模板级改动把懒加载无差别扫到所有图片(包括首屏 LCP 元素)是典型起因;CrUX 现场数据 p75 恶化确认真实用户影响,Lighthouse 实验数据确认机制与幅度。想拿现场级证据就用 PerformanceObserver 监听 largest-contentful-paint 条目。
诊断思路
先在 Performance 面板找 LCP 元素及其相对导航开始的到达时间;再统计服务 HTML 里 lazy 属性的分布,确认主图是否被一刀切波及;最后实验与现场对照:Lighthouse 复现机制、CrUX 验证人群影响。图片缺 width/height 会给迟到加载再叠一层布局偏移,fetchpriority 未设则主图即使 eager 也与其他资源竞争。
根因
懒加载把图片推迟到浏览器判断其接近视口,使其在加载管线中排在布局、脚本和其他资源之后。用在首屏 LCP 图片上,就推迟了页面最大的绘制——恰好是懒加载本想保护的指标。
修复与验证
首屏与屏外区别对待:主图 eager、显式宽高、fetchpriority=“high”;CSS 背景或脚本插入的主图用 ;第二屏起再 lazy 且同样带宽高——预留 aspect-ratio 空间让迟到的加载不再推挤布局。验证时重跑 Lighthouse 并观察 CrUX:LCP 回到改动前水平、屏外图片仍然推迟、CLS 因尺寸预留保持平坦。按猜测的折叠线把所有图都 eager 会伤到慢网络——从第二屏起用真实视口测得的分界再懒加载。
代码示例
<img src="hero.jpg" loading="lazy" alt="...">
new PerformanceObserver((list) => {
const e = list.getEntries().at(-1);
console.log('LCP element:', e.element, e.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });
<!-- hero: eager, high priority, dimensioned -->
<img src="hero.jpg" width="1600" height="600"
fetchpriority="high" alt="...">
<!-- below the fold: lazy, still dimensioned -->
<img src="gallery-1.jpg" width="800" height="600"
loading="lazy" alt="...">
<link rel="preload" as="image" href="hero.jpg"
fetchpriority="high">