有两个 Astro 版本改写了这道题的正确答案。响应式图片在 Astro 5.10 正式转正,于是 layout 属性和 priority 快捷写法成了稳定默认,不再是实验性开关。接着 Astro 6.1(2026 年 3 月 26 日) 加入了按编码器配置 Sharp 的能力,AVIF、WebP 的编码参数集中调一次就行,不必逐张图设。可大多数教程还停留在 5.10 之前的写法:手写 widths、手动加 loading="eager"。下面这套,是截至 2026 年 6 月在千篇规模内容站上真正扛得住的配置。
一句话结论
- 用
<Picture>配formats={['avif', 'webp']},剩下的浏览器交给<img>兜底。同等画质下 AVIF 比 WebP 小 20-30%,2026 年浏览器覆盖率约 95% 以上。 - 加
layout="constrained",让 Astro 自动生成srcset和sizes。正文图别再手写widths了。 - 给那张 LCP 图加
priority,一个属性就展开成loading="eager"+decoding="sync"+fetchpriority="high"。其余图片自动懒加载。 - 把 AVIF、WebP 的
effort在astro.config.mjs的image.service.config里集中配一次(6.1 新增),别再逐张图跟构建时间较劲。
Astro 5.10 与 6.1 改了什么
图片管线依旧在构建期跑 Sharp:生成多尺寸变体、转码格式、把 HTML 改写成带 srcset 的 <picture>。变的是你要手动配多少。
| 能力 | 5.10 之前的写法 | 2026 年 6 月的写法 |
|---|---|---|
| 响应式宽度 | 手写 widths={[400, 800, 1200]} + sizes | layout="constrained",Astro 自动推导 |
| LCP 图 | 分别写 loading="eager" + fetchpriority="high" | 一个 priority 属性 |
| 编码器调优 | 到处写逐图 quality | 全局 image.service.config 按编码器配(6.1) |
| 响应式样式 + CSP | 手动 | 哈希 CSS class,开箱兼容 CSP |
layout 取值为 constrained、full-width、fixed、none(默认 none)。注意是 constrained,不是 “responsive”——后者这个值根本不存在。densities 属性与 layout 互斥,二选一。
怎么判断图片出问题了
- Lighthouse 报 “Properly size images” 或 “Serve images in next-gen formats”。
- 移动端 LCP 超过 “Good” 门槛的 2.5 秒。
- 单篇文章页加载图片总量超过 600KB。
- 一眼看到本该是 AVIF 的原始 PNG 截图,体积是原来的五倍。
- 带宽账单被打回源站的
/_image?...请求占了大头,而不是走 CDN。
方案一:现代正文图
正文里的图用 <Picture> 配 layout="constrained"。不用再手写 widths 或 sizes——Astro 会根据源图尺寸和约束布局生成合理的 srcset:
---
import { Picture } from 'astro:assets';
import cover from '../assets/cover.png';
---
<Picture
src={cover}
alt="Astro 构建期图片管线示意图"
layout="constrained"
formats={['avif', 'webp']}
decoding="async"
/>
constrained 表示图片可以缩小适配容器,但永远不会渲染得比自身原始宽度更大——正好是定宽版心里正文图想要的行为。不设 layout 时,正文图默认懒加载(loading="lazy"),首屏以下的内容本就该如此。
如果不用 layout 还想手动控制,widths 必须配上对应的 sizes,否则构建会报错:
<Picture
src={cover}
alt="..."
widths={[400, 800, 1200]}
sizes="(max-width: 768px) 100vw, 800px"
formats={['avif', 'webp']}
/>
不管哪种写法,铁律是:绝不生成比版心还宽的变体。给 800px 的列出 2400px 的 AVIF,纯属白扔字节。
方案二:LCP 图用 priority
承担 Largest Contentful Paint 的那张图——hero、封面或首屏示意图——必须 eager 加载。把它懒加载,仍是内容站 LCP 退化的头号原因。从 Astro 5.10 起,你不用再手动接三个属性,一个 priority 布尔值搞定:
<Picture
src={hero}
alt="文章首图"
layout="full-width"
formats={['avif', 'webp']}
priority
/>
priority 会展开成 loading="eager"、decoding="sync" 和 fetchpriority="high"。每页只用在一张图上——也就是 LCP 元素。加在多张图上反而失效,因为浏览器真正能优先的只有一张。
如果 hero 渲染在某个组件深处、HTML 解析器早期看不到,就在页面 <head> 显式加 preload,让请求在初始解析阶段就发出去:
<link rel="preload" as="image" href={heroSrc.src} imagesrcset={heroSrcset} imagesizes="100vw" />
方案三:编码器配一次就好(Astro 6.1)
6.1 之前,你逐张图设 quality,编码器 effort 只能用 Sharp 的默认值。Astro 6.1 让你在 image.service.config 下集中设按编码器的默认值。effort 越高文件越小,代价是构建时间——图片上百张时这是个实打实的取舍:
import { defineConfig } from 'astro';
export default defineConfig({
image: {
layout: 'constrained',
service: {
config: {
avif: { effort: 4, chromaSubsampling: '4:2:0' },
webp: { effort: 5 },
jpeg: { mozjpeg: true },
png: { compressionLevel: 9 },
},
},
},
});
逐图 quality 仍然优先于全局,所以全局默认和单图覆盖可以共存。这里设 image.layout 会把 constrained 变成所有 <Image>、<Picture> 的默认值,于是各组件上的这个属性都能删掉。
方案四:远程图与 CDN 陷阱
Astro 也能优化远程图,但要先在 astro.config.mjs 把域名加进白名单:
export default defineConfig({
image: {
domains: ['images.unsplash.com'],
remotePatterns: [{ protocol: 'https' }],
},
});
远程图同样经过构建期 Sharp 处理,落到 dist/_astro/。如果部署到不保留 dist/_astro/ 的 serverless 平台,生产就会一堆坏图。必须真部署一次来验证,npm run preview 看不出来。上线后还要确认优化产物由 CDN 边缘提供并设长 TTL 缓存——/_image? 请求每次浏览都打回源站,正是带宽账单暴涨的常见原因。
容易踩的坑
- 用原始
<img>配 PNG/JPG,绕开管线。Astro 没法压缩、转码、加内容 hash。 - 写了
widths却不配sizes。Astro 构建期会报错;要么补sizes,要么改用layout。 - 传
layout="responsive"。这个值不存在;响应式布局叫constrained。 - LCP 图懒加载,或者把
priority同时加在好几张图上。 - 把
densities和layout一起用——两者互斥。 - 把截图当照片压。扁平 UI 截图用 PNG-8 或无损 AVIF,比默认质量的 WebP 还小。
- 生产里
_image?请求直接打回源站,而不是在 CDN 缓存。
FAQ
- AVIF 和 WebP 选哪个: 两个都发,用
formats={['avif', 'webp']}。AVIF 更小(同画质下比 WebP 小 20-30%),覆盖率已达约 95%;WebP(约 97%)兜住剩下的浏览器,在老硬件上解码更快。<img>兜底处理再剩下的。 - 响应式
layout属性还是实验性的吗: 不是。它在 Astro 5.10 已转正,不再需要experimentalLayout开关——在配置里设image.layout,或逐组件传layout即可。 priority到底做了什么: 它把loading="eager"、decoding="sync"、fetchpriority="high"一起设上。只用在那一张首屏 LCP 图上。- Astro 处理动图 WebP 或 GIF 吗: Sharp 默认不处理动画。要么直接发原图,要么转成 MP4/WebM,比动图 GIF 大约小 10 倍。
- 什么时候 Cloudinary 或 imgix 比自带管线划算: 图片超过约 1 万张,或者需要构建期算不出的实时变换。少于这个量,构建期管线更简单且免费。
- 加了图之后构建变慢了怎么办: Sharp 是 CPU 密集型,AVIF 的
effort是大头。在image.service.config里调低 AVIFeffort,并在 CI 之间缓存node_modules/.astro/,没改过的图就不会重新编码。
外部参考:Astro 图片指南 看当前属性,web.dev 优化 LCP 看方案二里 preload 背后的原理。