我花四年优化 Next.js 中的图像 - 2026年最佳实践

我花了过去四年时间在 Next.js 应用中优化图像,我会坦白说 -- 2026年的情况看起来和 next/image 首次推出时完全不同。Google 的核心网页指标阈值已经收紧,新的图像格式已经成熟,而 next/image 组件本身经历了多次重写。如果你的图像配置方式仍然和 2023 年一样,那你在性能(以及排名)上留下了机会。

这不是对 Next.js 文档的重述。这是我从发布数十个生产网站中学到的 -- LCP 分数真正重要的地方 -- 其中图像加载时间相差 200ms 意味着在第一页和第三页之间的差别。

目录

Next.js Image Optimization for Core Web Vitals in 2026

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 时发生的事情的神秘面纱。理解这个管道有助于你做出更好的优化决策。

请求流

  1. 构建时:Next.js 生成一个指向 /_next/image?url=...&w=...&q=...<img> 标签的 HTML
  2. 第一个请求:Next.js 图像优化 API 接收请求,获取原始图像,调整大小,转换格式,并缓存结果
  3. 后续请求:缓存的版本直接被提供

在 Next.js 15(截至 2026 年初的当前稳定版),图像优化器在 Node.js 环境中默认使用 sharp。在 Vercel 上,它使用他们的基于边缘的图像优化服务。在其他平台上,它根据你的配置回退到 sharpsquoosh

// 基本用法 -- 但在这个简单的代码后有很多事情正在发生
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。

Next.js Image Optimization for Core Web Vitals in 2026 - architecture

格式战争: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 中的响应式图像并不难,但它们确实需要理解 deviceSizesimageSizessizes 属性如何协同工作。

`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。

我在每次审计中都看到的常见错误

  1. 为装饰性 SVG 使用 next/image:只需使用 <img> 标签或内联 SVG。优化管道增加了零收益的开销。

  2. 全局设置 unoptimized,因为"图像看起来模糊":改为修复质量设置。unoptimized 绕过所有内容。

  3. 忘记 alt 文本:这不仅仅是可访问性 -- Google 的图像搜索推动流量,它需要 alt 文本来索引你的图像。

  4. 不设置 minimumCacheTTL:默认值是 60 秒。这意味着你的服务器在负载下每分钟重新优化相同的图像。至少将其设置为 2592000(30 天)。

  5. 使用巨大的源图像:上传 6000x4000px DSLR 照片并期望 Next.js 处理它。预处理你的源图像为最大显示大小的 2 倍。

  6. 忽略网络标签:打开 DevTools,按 Img 过滤,按大小排序。你会在 30 秒内找到问题。

如果你在生产网站上为这些问题而苦恼,那正是我们解决的问题。查看我们的定价直接联系 -- 我们进行性能审计作为独立参与。

常见问题

next/image 会自动将图像转换为 AVIF 吗? 是的,如果你在 next.config.jsimages.formats 数组中有 'image/avif'(自 Next.js 14 起默认包含)。当浏览器发送包含 image/avifAccept 标头时,转换会按需进行。第一个请求由于编码而较慢,但随后的请求从缓存中提供。

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 年以来在所有主要浏览器中一直是稳定的。