先把当时的情况摆出来。详情页主图是 1200x900 的 jpg,Lighthouse 12.2 跑移动配置,LCP 报 4.6 秒,第 4 项提示写着「发现图片可以更早加载」。页面 head 里其实已经手写了 preload,href 和 img 的 src 看起来一模一样,改了三次都没变化。

真正麻烦的地方在于,几个原因的现象几乎一样。preload 的 href 里带 ?w=1200 参数,而 src 渲染出来是 ?w=1200&q=80 完全不同的地址。也可能是preload 没有写 imagesrcset 和 imagesizes,响应式图片选了另一份文件。

不容易想到的是,主图在 CSS 里被包成 background-image,preload 加载的那张根本没参与渲染。还有一种情况,preload 排在阻塞脚本之后,浏览器发现它时已经到 LCP 时刻。

动手时先用 DevTools 的 Network 面板筛 Initator 里的 preload,看加载地址和实际渲染地址是否一致

再往下把 preload 的地址和页面渲染出来的 img src 逐字对比

curl -s https://www.example.com/p/1024 | grep -o 'rel=.preload.[^>]*'

接着确认图片有没有走响应式选择,检查 imagesrcset 是否输出

curl -s https://www.example.com/p/1024 | grep -o 'imagesrcset="[^"]*"'

剩下的就是把 preload 移到 head 最前并和 img 用同一个地址生成函数

grep -n 'preload' templates/detail.html

怎么算真的好了,看的是同一批现象。Network 里 preload 的请求和 LCP 元素用的是同一条地址,瀑布图上它前移到 HTML 之后三行内,LCP 从 4.6 秒降到 2.4 秒。

补一句。同名不同参的 preload 在报告里看不出来,报错也不会有,只能把两个地址并排贴出来比字符。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189