用 Astro 的图片组件把首屏压到 100KB 以内

从 480KB 到 96KB:一次真实的图片优化记录,包括格式选择、尺寸生成、懒加载策略,以及 LCP 的实测变化。

用 Astro 的图片组件把首屏压到 100KB 以内

这个站原来首屏要下 480KB 的图片,换成 Astro 的 <Image> + AVIF 之后降到 96KB,LCP 从 2.4s 到 1.1s。

记一下具体做了什么。

先看问题在哪

用 Lighthouse 跑一遍,问题很清楚:

LCP 元素:首屏插画 (316×316)
  └─ 资源大小 412 KB(PNG)
  └─ 阻塞时间 1.3 s
  └─ 未使用的响应式尺寸(手机上按桌面尺寸下载)

三个问题:格式太老、尺寸没适配、加载优先级不对。

改法

---
import { Image } from 'astro:assets';
import hero from '@/assets/hero.png';
---
<Image
	src={hero}
	alt="站点吉祥物"
	widths={[200, 316, 480]}
	sizes="(max-width: 960px) 200px, 316px"
	format="avif"
	loading="eager"
	fetchpriority="high"
/>

产物:

<img
  src="/_image?f=avif&w=316&h=316"
  srcset="/_image?f=avif&w=200 200w, /_image?f=avif&w=316 316w, /_image?f=avif&w=480 480w"
  sizes="(max-width: 960px) 200px, 316px"
  width="316" height="316"
  alt="站点吉祥物" loading="eager" fetchpriority="high" decoding="async">

关键是三个属性:

  • width / height:浏览器提前知道比例,避免布局抖动(CLS)
  • sizes:告诉浏览器按哪个宽度下载,手机就不会下桌面版
  • fetchpriority="high":LCP 图片要显式提权

尺寸怎么定

我的经验值:

用途宽度档位格式
头像 / 图标64 / 128SVG 优先,否则 AVIF
卡片封面400 / 640 / 800AVIF + WebP 兜底
文章大图800 / 1200 / 1600AVIF + WebP 兜底
首屏主图实际显示宽度 × 1.5AVIF

不要超过 1600px。 再大对观感没有帮助,只是浪费流量。

实测结果

指标优化前优化后变化
首屏图片体积412 KB84 KB−80%
总传输480 KB96 KB−80%
LCP2.4 s1.1 s−54%
CLS0.120.00消除

别忘了 OG 图

社交平台分享卡片的图是另一套逻辑:尺寸固定 1200×630,格式用 PNG 更稳(有些平台的解析器对 WebP 支持不好)。

我的做法是构建期用 sharp 生成,一次生成永久缓存:

await sharp(svgBuffer).resize(1200, 630).png({ compressionLevel: 9 }).toFile('og.png');

这样就完成了从「图片拖慢首屏」到「图片完全不是瓶颈」的转变。下一步打算试试 Cloudflare Images 做运行时变换,把构建产物再瘦一圈。

评论区还没开张 —— 想开启的话,把 src/data/site.ts 里FEATURES.comments 的 enabled 设为 true 并填入 giscus 配置即可。

也许你还想看