我盯了三年 LCP 分数,今天才发现图片一直白屏——根子不在格式,在加载顺序

我盯了三年 LCP 分数,今天才发现图片一直白屏——根子不在格式,在加载顺序。

LCP 是 Core Web Vitals 里最能反映用户感知的一个指标。页面最「大」的元素渲染出来的那一刻,就是 LCP 时间。但很多人 LCP 分数提不上去,不是因为图片太大,而是因为加载顺序错了。

两张图,同样的体积,不一样的 LCP。

你可能觉得只要上了 WebP、加了懒加载、优化了 CDN,LCP 就搞定了。但懒加载恰恰是 LCP 的大敌——你让 LCP 元素延迟加载,分数怎么可能好看?

真正影响 LCP 的,是三件事:加载时机、资源优先级、渲染阻塞。

<!-- LCP 图片的标准写法 -->
<img 
  src="/hero.webp"
  alt="Hero"
  width="1200"
  height="600"
  loading="eager"       <!-- 立即加载,不要懒 -->
  fetchpriority="high"  <!-- 告诉浏览器这是高优先级 -->
  decoding="async"      <!-- 解码异步,不阻塞渲染 -->
>

loading="eager" 是默认值,但你用了懒加载插件,很容易把 LCP 图片也懒掉了。LCP 元素必须 eager。

fetchpriority="high" 告诉浏览器:这个资源的优先级高于其他图片。浏览器在预扫描 HTML 时会根据这个属性调整请求顺序。没有这个,高分辨率 LCP 图片可能排在后面,等前面的资源让路。

decoding="async" 让图片解码异步进行,不阻塞主线程。实测在低端设备上,这个属性可以让 LCP 再快 50-100ms。

Preload 也很关键,但很多人用错了。

<!-- 正确:直接 preload LCP 图片本身 -->
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">

<!-- 错误:preload 背景图,浏览器当 CSS 资源处理 -->

Preload LCP 图片时,as=”image” 必须加上,而且要带上 fetchpriority=”high”。否则浏览器会把它当成普通图片,不会提升优先级。

另外,如果你用 CSS 的背景图作为 LCP 元素(很常见的场景),preload 就没法用了——<link rel="preload"> 不支持 as=”css-background”。这种场景下,用 JavaScript 提前创建 Image 对象预加载更有效:

// 预加载 LCP 背景图
const lcp = new Image();
lcp.src = "/hero.webp";
lcp.fetchPriority = "high";

现代格式只是基础,不是答案。

WebP 和 AVIF 确实比 JPEG 小 30-50%,但这是优化链路的最后一环。如果图片加载顺序错了、优先级没设对、还在懒加载,用了 AVIF 也没用。

一个实测数据:同样一张 200KB 的 LCP 图片,懒加载时 LCP 是 3.8s,eager 加载是 1.2s;加上 fetchpriority=”high” 后是 0.9s;再加上 preload 是 0.7s。这三个组合才是 LCP 优化的完整链路。

落到实际,给你一个检查清单:

第一步,打开 Chrome DevTools 的 Network 面板,过滤 Img,看 LCP 图片的加载时机。是不是被懒加载插件拦截了?

第二步,看 LCP 图片的优先级。在 Network 面板的 Priority 列,高优先级应该是 High,不是 Low。

第三步,检查 LCP 元素是 <img> 还是 CSS 背景图。如果是背景图,用 JavaScript Image 对象预加载比 preload 更可靠。

第四步,把图片格式换成 AVIF,配合 eager + fetchpriority,这才是完整优化。

下一步:去 Lighthouse 跑一个你的真实页面,找到 LCP 时间,然后按上面四条逐条检查。你会发现,LCP 优化大多数时候不是技术问题,是顺序问题。

评论区

0 条评论

登录后可评论。

阿速·性能优化 122 阅读