2026年Next.js图像优化与Core Web Vitals
我花四年优化 Next.js 中的图像 - 2026年最佳实践
我花了过去四年时间在 Next.js 应用中优化图像,我会坦白说 -- 2026年的情况看起来和 next/image 首次推出时完全不同。Google 的核心网页指标阈值已经收紧,新的图像格式已经成熟,而 next/image 组件本身经历了多次重写。如果你的图像配置方式仍然和 2023 年一样,那你在性能(以及排名)上留下了机会。
这不是对 Next.js 文档的重述。这是我从发布数十个生产网站中学到的 -- LCP 分数真正重要的地方 -- 其中图像加载时间相差 200ms 意味着在第一页和第三页之间的差别。
目录
- 2026年核心网页指标:有什么改变
- next/image 实际上如何在后台工作
- LCP 问题:为什么你的英雄图像正在杀死你的分数
- 格式战争:2026 年 AVIF vs WebP vs JPEG XL
- 正确处理响应式图像
- CDN 和边缘优化策略
- 测量重要的东西:工具和基准
- 真正推动进展的高级技术
- 我在每次审计中都看到的常见错误
- 常见问题

2026年核心网页指标:有什么改变
Google 在 2025 年底更新了核心网页指标阈值,这些变化并不是微不足道的。以下是当前的情况:
| 指标 | 2023年"优秀"阈值 | 2026年"优秀"阈值 | 测量内容 |
|---|---|---|---|
| LCP | ≤ 2.5秒 | ≤ 2.0秒 | 最大内容绘制 |
| INP | ≤ 200毫秒 | ≤ 150毫秒 | 交互到下一次绘制 |
| CLS | ≤ 0.1 | ≤ 0.1 | 累积布局偏移 |
| TTFB | 不适用(不是 CWV) | 非正式 ≤ 600毫秒 | 首字节时间 |
LCP 阈值从 2.5 秒下降到 2.0 秒对图像丰富的网站打击最大。半秒听起来不是很多,直到你意识到 60% 以上的页面,LCP 元素就是一张图像。通常是英雄图像、产品照片或特色文章缩略图。
INP 替代 FID 已经生效,但收紧的 150 毫秒阈值意味着重型 JavaScript 包 -- 包括配置不当的图像延迟加载脚本 -- 会破坏你的交互性分数。
CLS 保持不变,这是个好消息。但当图像没有明确的尺寸时,它们仍然是布局偏移的第一原因。
为什么这对 Next.js 特别重要
Next.js 应用通常按天生就是 JavaScript 密集的。你在发布 React,你在发布框架代码,如果你不小心,你也在发布客户端的图像优化逻辑。更严格的 LCP 预算和 React 应用的 JS 开销的组合意味着你比静态 HTML 网站的出错空间更小。
这正是为什么我们专注于 Next.js 开发 -- 该框架提供了不可思议的工具,但只有当你知道如何配置它们时。
next/image 实际上如何在后台工作
让我们揭开使用 <Image /> 来自 next/image 时发生的事情的神秘面纱。理解这个管道有助于你做出更好的优化决策。
请求流
- 构建时:Next.js 生成一个指向
/_next/image?url=...&w=...&q=...的<img>标签的 HTML - 第一个请求:Next.js 图像优化 API 接收请求,获取原始图像,调整大小,转换格式,并缓存结果
- 后续请求:缓存的版本直接被提供
在 Next.js 15(截至 2026 年初的当前稳定版),图像优化器在 Node.js 环境中默认使用 sharp。在 Vercel 上,它使用他们的基于边缘的图像优化服务。在其他平台上,它根据你的配置回退到 sharp 或 squoosh。
// 基本用法 -- 但在这个简单的代码后有很多事情正在发生
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Product hero shot"
width={1200}
height={630}
priority
quality={80}
/>
);
}
那个 priority 属性所做的比你想象的多。它向 HTML 添加 fetchpriority="high",禁用延迟加载,并在 <head> 中生成一个预加载 <link> 标签。我们稍后会回到为什么这对 LCP 很重要。
大多数人从未接触过的配置
你的 next.config.js(或 next.config.ts,如果你已经迁移)有一个 images 键,可以控制一切:
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 31536000, // 1 year in seconds
dangerouslyAllowSVG: false,
remotePatterns: [
{
protocol: 'https',
hostname: 'your-cms.com',
pathname: '/assets/**',
},
],
},
};
formats 数组的顺序很重要。Next.js 会先尝试 AVIF,然后回退到 WebP。AVIF 编码速度较慢但产生较小的文件 -- 这个权衡值得理解。
LCP 问题:为什么你的英雄图像正在杀死你的分数
这是我在几乎每次审计中看到的情景:一张漂亮的英雄图像,在折叠线上方,需要 3 秒以上才能绘制。开发者使用了 next/image,认为他们已经完成了,然后继续。但分数很糟糕。
通常的罪魁祸首:
1. 缺少 `priority` 属性
默认情况下,next/image 会延迟加载所有内容。这对折叠线下方的图像很好,但对你的 LCP 元素来说是灾难性的。没有 priority,浏览器在 JavaScript 水合和交集观察者启动后才发现该图像。
// ❌ 这会延迟加载你的 LCP 图像
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} />
// ✅ 这会预加载它
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} priority />
2. 用低质量值过度压缩
我看过团队设置 quality={50},认为较小 = 较快。但如果图像看起来模糊,Chrome 的 LCP 算法仍然必须等待它完全绘制。在高 DPI 屏幕上,质量低于 70 通常会触发可见的伪影,使设计看起来很廉价。
我的经验法则:照片质量为 75-85,包含文本或锐边的图像质量为 90+。
3. 不正确使用 `sizes`
sizes 属性告诉浏览器在 CSS 被解析之前请求哪个图像宽度。没有它,Next.js 默认为 100vw,这意味着移动设备下载桌面大小的图像。
<Image
src="/hero.jpg"
alt="Hero"
fill
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px"
/>
这个单一的属性改变给了我最大的 LCP 改进 -- 在移动设备上有时是 400-800ms。

格式战争:2026 年 AVIF vs WebP vs JPEG XL
格式情况已经相当稳定。以下是我们所处的位置:
| 格式 | 浏览器支持 (2026) | 压缩 | 编码速度 | 最佳用途 |
|---|---|---|---|---|
| AVIF | ~95% 全球范围 | 优秀(比 WebP 小 30-50%) | 缓慢 | 照片、英雄图像 |
| WebP | ~98% 全球范围 | 良好(比 JPEG 小 25-35%) | 快速 | 通用 |
| JPEG XL | ~45%(Chrome 已删除) | 优秀 | 中等 | 不推荐用于网络 |
| JPEG | 通用 | 基准 | 快速 | 仅回退 |
| PNG | 通用 | 照片效果差 | 快速 | 透明度、屏幕截图 |
JPEG XL 有一个有前景的规范,但 Chrome 在 2023 年底决定删除支持,有效地对网络使用中止了它。Safari 添加了支持,Firefox 有部分支持,但你不能依赖它。
我的建议:设置 formats: ['image/avif', 'image/webp'] 然后忘记它。Next.js 通过 Accept 标头自动处理内容协商。
AVIF 编码成本
以下是文档不够强调的东西:AVIF 编码是 CPU 密集型的。在对你的 Next.js 服务器的第一个请求上,编码 1200px AVIF 图像在中等服务器上可能需要 2-5 秒。第一个访客承担成本。
减轻这种情况的策略:
- 在构建时预生成使用
next export或自定义构建脚本 - 使用具有内置图像优化的 CDN(Cloudflare Images、Imgix、Cloudinary)
- 预热你的缓存部署后使用脚本打击所有关键图像 URL
# 简单的缓存预热脚本
#!/bin/bash
URLs=("https://yoursite.com/_next/image?url=%2Fhero.jpg&w=1200&q=80"
"https://yoursite.com/_next/image?url=%2Fhero.jpg&w=750&q=80")
for url in "${URLs[@]}"; do
curl -s -o /dev/null -H "Accept: image/avif,image/webp" "$url"
echo "Warmed: $url"
done
正确处理响应式图像
Next.js 中的响应式图像并不难,但它们确实需要理解 deviceSizes、imageSizes 和 sizes 属性如何协同工作。
`fill` 布局模式
对于你不知道构建时纵横比的图像(CMS 内容、用户上传),使用 fill 属性:
<div className="relative aspect-[16/9] w-full">
<Image
src={post.featuredImage}
alt={post.title}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
具有 relative 定位和纵横比的父 div 至关重要。没有它,fill 图像会折叠为零高度,你会得到一个会让你畏缩的 CLS 分数。
使用 `` 的美术指导
有时你需要不同屏幕尺寸的不同裁剪。next/image 本身不支持 <picture>,但你可以绕过它:
// 美术指导解决方案
export function ResponsiveHero({ mobileSrc, desktopSrc, alt }) {
return (
<>
<div className="block md:hidden relative aspect-[9/16] w-full">
<Image src={mobileSrc} alt={alt} fill priority sizes="100vw" />
</div>
<div className="hidden md:block relative aspect-[16/9] w-full">
<Image src={desktopSrc} alt={alt} fill priority sizes="100vw" />
</div>
</>
);
}
是的,这会下载两个图像的 HTML,但只有一个渲染,隐藏的不会加载感谢延迟加载默认值(你只会对匹配视口的应用 priority)。
CDN 和边缘优化策略
如果你是自我托管 Next.js(许多团队都是),你需要一个图像 CDN 策略。
选项 1:让 Vercel 处理它
Vercel 的图像优化在边缘运行。对于大多数项目,这是最简单的路径。截至 2026 年,Vercel 的专业计划包括 5,000 个优化的源图像,额外的图像为每 1,000 个 $5。企业计划有自定义定价。
选项 2:外部图像优化服务
Cloudinary、Imgix 和 Cloudflare Images 都通过 loader 属性或自定义加载器与 Next.js 一起工作:
// next.config.js with Cloudinary
module.exports = {
images: {
loader: 'custom',
loaderFile: './lib/cloudinary-loader.js',
},
};
// lib/cloudinary-loader.js
export default function cloudinaryLoader({ src, width, quality }) {
const params = [
`w_${width}`,
`q_${quality || 'auto'}`,
'f_auto',
'c_limit',
];
return `https://res.cloudinary.com/your-cloud/image/upload/${params.join(',')}${src}`;
}
| 服务 | 免费层 | 专业定价 (2026) | 边缘节点 | AVIF 支持 |
|---|---|---|---|---|
| Cloudinary | 25 credits/月 | $89/月 (25GB) | 60+ | 是 |
| Imgix | 无 | $100/月 (100GB) | 全球 | 是 |
| Cloudflare Images | 无 | $5/月 (100K 变体) | 310+ | 是 |
| Vercel(内置) | 1,000 张图像 (Hobby) | 包含在专业版中 | 边缘 | 是 |
对于我们的 headless CMS 开发 项目,我们通常使用 Cloudinary 或 CMS 的内置图像管道(Sanity、Contentful 和 Hygraph 都有体面的图像 API)。
选项 3:Cloudflare Polish + Next.js
如果你已经在 Cloudflare 后面,他们的 Polish 功能可以在边缘处理格式转换。你会禁用 Next.js 图像优化并让 Cloudflare 处理工作:
module.exports = {
images: {
unoptimized: true, // 让 Cloudflare 处理它
},
};
我不太喜欢这种方法,因为你会失去 next/image 提供的响应式尺寸,但它适用于更简单的设置。
测量重要的东西:工具和基准
你不能改进你不测量的东西。这是我的测试堆栈:
实验工具
- Chrome DevTools Lighthouse(2026 年 v12):仍然是起点。在无扩展的隐身窗口中运行它。
- WebPageTest:将其设置为 Dulles, VA,在 Moto G Power 上,有 4G。这代表一个现实的"慢"用户。
- Unlighthouse:批量扫描你的整个网站。对于捕捉你忘记的页面很惊人。
现场数据
- Chrome UX Report (CrUX):Google 用于排名信号的实际数据。可在 PageSpeed Insights 和 BigQuery 中获得。
- web-vitals.js:将其添加到你的应用以收集真实用户指标:
// app/layout.tsx
import { onLCP, onINP, onCLS } from 'web-vitals';
if (typeof window !== 'undefined') {
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
}
在生产环境中,将这些发送到你的分析平台而不是 console.log。我们使用 Vercel Speed Insights 和一个写入 BigQuery 的自定义端点的组合。
2026 年的基准目标
基于我们今年审计的网站,以下是图像丰富的 Next.js 网站的"好"样子:
- 移动 LCP (p75):< 1.8 秒(在 2.0 秒阈值下给你缓冲区)
- 折叠线上方的总图像权重:< 200KB
- 英雄图像加载时间:4G 上 < 800ms
- 来自图像的 CLS:0
真正推动进展的高级技术
使用 BlurHash 的模糊占位符
Next.js 对静态导入本身支持 placeholder="blur"。对于动态图像(来自 CMS),你需要生成模糊数据 URL:
import { getPlaiceholder } from 'plaiceholder';
export async function getStaticProps() {
const { base64 } = await getPlaiceholder('/path/to/image.jpg');
return {
props: { blurDataURL: base64 },
};
}
// 在组件中
<Image
src={dynamicUrl}
alt="Dynamic image"
fill
placeholder="blur"
blurDataURL={blurDataURL}
/>
这不会直接改进 LCP,但它会大大改善感知的性能并防止 CLS。
HTTP/3 和早期提示
如果你的 CDN 支持 HTTP/3(Cloudflare、Fastly 和 Vercel 都支持),你可以使用 103 Early Hints 在 HTML 文档完全生成之前开始发送 LCP 图像:
// middleware.ts
import { NextResponse } from 'next/server';
export function middleware(request) {
const response = NextResponse.next();
if (request.nextUrl.pathname === '/') {
response.headers.set(
'Link',
'</hero.avif>; rel=preload; as=image; type="image/avif"'
);
}
return response;
}
使用 CSS `content-visibility` 的骨架加载
对于包含许多图像的长页面,content-visibility: auto 告诉浏览器完全跳过屏幕外内容的渲染:
.image-grid-item {
content-visibility: auto;
contain-intrinsic-size: 300px 200px; /* Estimated size */
}
这在我们去年优化的产品列表页面上将 INP 减少了 30-40ms。
我在每次审计中都看到的常见错误
为装饰性 SVG 使用
next/image:只需使用<img>标签或内联 SVG。优化管道增加了零收益的开销。全局设置
unoptimized,因为"图像看起来模糊":改为修复质量设置。unoptimized绕过所有内容。忘记
alt文本:这不仅仅是可访问性 -- Google 的图像搜索推动流量,它需要 alt 文本来索引你的图像。不设置
minimumCacheTTL:默认值是 60 秒。这意味着你的服务器在负载下每分钟重新优化相同的图像。至少将其设置为2592000(30 天)。使用巨大的源图像:上传 6000x4000px DSLR 照片并期望 Next.js 处理它。预处理你的源图像为最大显示大小的 2 倍。
忽略网络标签:打开 DevTools,按
Img过滤,按大小排序。你会在 30 秒内找到问题。
如果你在生产网站上为这些问题而苦恼,那正是我们解决的问题。查看我们的定价或直接联系 -- 我们进行性能审计作为独立参与。
常见问题
next/image 会自动将图像转换为 AVIF 吗?
是的,如果你在 next.config.js 的 images.formats 数组中有 'image/avif'(自 Next.js 14 起默认包含)。当浏览器发送包含 image/avif 的 Accept 标头时,转换会按需进行。第一个请求由于编码而较慢,但随后的请求从缓存中提供。
AVIF 与 WebP 相比实际上将图像文件大小减少了多少? 在我们对数百个生产图像的测试中,AVIF 平均比 WebP 小 30-50%,比等效视觉质量的 JPEG 小 50-70%。收益在摄影内容上最显著。对于屏幕截图或包含文本的图像,差异缩小至 15-25%。
我应该对多个图像使用 priority 吗?
谨慎使用 -- 仅在真正折叠线上方且在初始加载时可见的图像上。向 2-3 个以上的图像添加 priority 会削弱目的,因为浏览器无法同时优先考虑所有内容。对于你的主页英雄和可能一个徽标,就这样。
为什么我的 LCP 即使使用 next/image 和 priority 仍然很慢? 最常见的原因是你的服务器响应时间 (TTFB) 正在吃掉你的预算。如果你的 Next.js 服务器需要 800ms 才能响应,你只有 1.2 秒留给图像加载和绘制。其他罪魁祸首:阻止渲染的 CSS、延迟水合的大型 JavaScript 包,或图像源在慢源服务器上。
我可以对静态导出(next export)使用 next/image 吗?
不能使用内置优化。静态导出需要 images.unoptimized: true 或指向外部服务(如 Cloudinary 或 Imgix)的自定义加载器。这是我们有时推荐 Astro 用于纯静态网站的原因之一 -- 其图像处理不需要运行服务器。
我如何使用 next/image 处理来自 headless CMS 的图像?
将 CMS 的图像域添加到配置中的 images.remotePatterns。大多数 headless CMS 平台(Sanity、Contentful、Storyblok、Hygraph)都有自己的图像转换 API。你可以通过自定义加载器使用这些或让 Next.js 处理优化。对于 headless CMS 项目,我们通常倾向于 CMS 的本地管道,因为它减少了服务器负载。
图像优化对核心网页指标排名信号的影响是什么? Google 在 2025 年确认核心网页指标仍然是排名信号,尽管内容相关性仍然占主导地位。也就是说,对于竞争查询,其中顶部结果的内容质量相似,CWV 可以是平局破坏者。我们看到网站在修复主要由未优化图像引起的 LCP 问题后移动 3-8 个位置。
我应该对所有折叠线下方的图像进行延迟加载吗?
是的,Next.js 默认这样做(除非你添加 priority)。本地 loading="lazy" 属性是 next/image 在后台使用的。不再需要基于 JavaScript 的延迟加载库 -- 浏览器本地延迟加载自 2022 年以来在所有主要浏览器中一直是稳定的。