Lighthouse 性能评分低,懒加载图片为啥没生效?
我用 Vue 做了个图片列表页,明明加了懒加载,但 Lighthouse 跑出来还是说“延迟加载首屏外的图片”没通过,性能分卡在 60 多。是不是我的写法有问题?
我试过把 loading=”lazy” 加在 img 标签上,也确认图片都在首屏以下,但 Lighthouse 就是不认。
<template>
<div v-for="item in images" :key="item.id">
<img :src="item.url" loading="lazy" alt="示例图" />
</div>
</template>
另外有个关键点:如果首屏内有任何图片用了
loading="lazy",这反而是扣分项。首屏图片应该直接加载,懒加载是给首屏之外的用的。还有个常见坑:图片没写宽高会导致 CLS(布局偏移),Lighthouse 同样会扣分。
改法是这样的:
第一,确保首屏图片不用 lazy loading。你可以搞两个列表,首屏的正常渲染,首屏以下的用 lazy:
第二,所有 img 标签都带上 width 和 height 属性,防止布局偏移。
第三,如果你想更可控,可以用 IntersectionObserver 自己写个懒加载指令,或者用 vue-lazyload 这种成熟库。
还有个事提醒一下:
:src="item.url"这里如果 url 是用户可控的内容,记得做好防止注入,虽然图片 src 注入危害比 script 小,但稳妥点没坏处。loading="lazy"确实加上了,但 Lighthouse 检测的是另一种情况。问题在于你的图片一上来就把
src设置好了,浏览器解析 HTML 的时候可能直接就开始请求图片资源了,原生懒加载的触发时机 Lighthouse 有时候抓不到。靠谱的做法是用
data-src先把真实地址存起来,等图片进入视口再赋值给src。给你一个 IntersectionObserver 的实现方案:这样写 Lighthouse 肯定能过,图片只有真正进入视口附近 100px 才会发起请求。
还有几个细节要注意。如果你用 vue-lazyload 这种库也行,但自己写 IntersectionObserver 更轻量,性能开销更小,不用引入额外依赖。记得加个
rootMargin提前加载,用户体验会好很多,不然用户滚动的时候图片会闪一下才出来。另外检查一下你的图片有没有设置宽高,没设置的话会导致布局抖动,CLS 那一项也要扣分的。把宽高写死或者用 aspect-ratio 撑开,这个对性能评分影响挺大的。