Back

如何在 Next.js 中优化图片以提升性能

如何在 Next.js 中优化图片以提升性能

图片通常占据网页总大小的 50-70%,直接影响核心 Web 指标(Core Web Vitals),如最大内容绘制(Largest Contentful Paint,LCP)和累积布局偏移(Cumulative Layout Shift,CLS)。糟糕的图片处理会拖累你的 Lighthouse 分数,增加跳出率,并损害 SEO 排名——即使你的 JavaScript 已经完美优化。

本指南涵盖了使用内置 next/image 组件进行 Next.js 图片优化的内容,从基础实现到高级 CDN 集成和缓存策略。你将学习如何交付响应式、快速加载的图片,从而改善性能指标和用户体验。

核心要点

  • next/image 组件自动将图片转换为 WebP 和 AVIF 等现代格式,文件大小减少 25-35%
  • 适当的图片优化可以将 LCP 改善 50%,并将带宽成本降低 60%
  • 在首屏图片上使用 priority 属性并配置响应式尺寸可以防止布局偏移
  • 自定义加载器(loader)可以为高流量应用集成专业的图片 CDN

为什么 next/image 组件对性能至关重要

next/image 组件不仅仅是 HTML <img> 标签的包装器——它是一个自动化的优化管道,处理现代图片交付的繁重工作。

核心性能特性

自动格式转换:当浏览器支持时,Next.js 会提供 WebP 和 AVIF 格式,与 JPEG/PNG 相比,在不损失质量的情况下将文件大小减少 25-35%。

响应式图片生成:该组件在构建时或按需创建多个图片尺寸,确保移动用户不会下载桌面尺寸的图片。

内置懒加载:首屏下方的图片仅在用户滚动到附近时才加载,减少初始页面重量并改善首次内容绘制(First Contentful Paint,FCP)。

防止布局偏移:通过要求 width 和 height 属性(或使用 fill 属性),组件在图片加载前预留空间,消除 CLS 问题。

基础实现和必要属性

从一个涵盖 80% 使用场景的简单实现开始:

import Image from 'next/image'

export default function Hero() {
  return (
    <Image
      src="/hero-banner.jpg"
      alt="Product showcase"
      width={1200}
      height={600}
      priority // Load immediately for LCP optimization
    />
  )
}

何时使用关键属性

priority:将此属性添加到影响 LCP 的首屏图片上。它会禁用懒加载并添加预加载链接。谨慎使用——每页仅用于 1-2 张关键图片。

sizes:对于响应式图片至关重要。告诉浏览器根据视口宽度下载哪个图片尺寸:

<Image
  src="/product.jpg"
  alt="Product"
  width={800}
  height={600}
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px"
/>

placeholder=“blur”:在主图片加载时显示低质量占位符。对于静态导入,Next.js 会自动生成 blurDataURL:

import heroImage from '@/public/hero.jpg'

<Image
  src={heroImage}
  alt="Hero"
  placeholder="blur"
  // blurDataURL generated automatically for static imports
/>

使用 remotePatterns 配置远程图片

对于来自外部源的图片,在 next.config.js 中配置 remotePatterns(旧的 domains 设置已被弃用):

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
}

此安全功能可防止恶意图片请求,同时允许特定的外部源。

使用 CDN 和自定义加载器进行高级优化

对于高流量应用,使用自定义加载器集成 Cloudinary 或 Imgix 等专业图片 CDN:

// lib/imageLoader.js
export default function cloudinaryLoader({ src, width, quality }) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}/${src}`
}

// Component usage
<Image
  loader={cloudinaryLoader}
  src="product.jpg"
  alt="Product"
  width={400}
  height={300}
/>

最佳性能的缓存策略

Next.js 默认设置激进的缓存头:

Cache-Control: public, max-age=31536000, immutable

对于动态内容,在 next.config.js 中覆盖这些设置:

module.exports = {
  async headers() {
    return [
      {
        source: '/_next/image(.*)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=86400, stale-while-revalidate=604800',
          },
        ],
      },
    ]
  },
}

生产环境最佳实践

使用真实数据衡量影响:使用 Lighthouse 和 WebPageTest 跟踪 LCP 改进。正确优化的主图可以将 LCP 减少 1-2 秒。

平衡质量和文件大小:将 quality={75} 作为起点。测试视觉质量与文件大小节省的平衡——从 100 降至 75 通常可以节省 40% 的大小,而视觉影响很小。

适当处理不同的图片类型:对 SVG 和已优化的资源使用 unoptimized:

<Image
  src="/logo.svg"
  alt="Logo"
  width={200}
  height={50}
  unoptimized
/>

TypeScript 实现类型安全:导入图片以自动检测尺寸并进行类型检查:

import type { StaticImageData } from 'next/image'
import productImage from '@/public/product.jpg'

interface ProductCardProps {
  image: StaticImageData
  alt: string
}

常见故障排除问题

“Invalid src prop” 错误:确保在 remotePatterns 中配置了远程域名,或使用自定义加载器。

高 DPI 显示器上图片模糊:检查源图片至少是显示尺寸的 2 倍,并避免低于 70 的激进质量设置。

构建时间增加:对于拥有数百张图片的网站,考虑使用按需优化而不是构建时处理,或使用外部服务实现自定义加载器。

结论

通过 next/image 组件进行 Next.js 图片优化可以以最少的配置提供即时的性能提升。从基础开始——适当的尺寸、懒加载和格式转换——然后随着流量规模的增长,逐步加入 CDN 集成和自定义加载器等高级技术。

关键是衡量实际影响:正确优化的图片可以将 LCP 改善 50%,将带宽成本降低 60%,并显著提升你的核心 Web 指标分数。首先关注首屏图片,然后系统地优化其余的图片管道。

常见问题

不可以,出于安全考虑,你必须在 next.config.js 中使用 remotePatterns 配置允许的域名。这可以防止恶意行为者将你的应用用作图片代理。你也可以通过自定义加载器绕过此限制。

对于高 DPI 屏幕,源图片应至少是显示尺寸的 2 倍。同时检查你的质量设置是否过低。质量设置为 75-85 通常能在文件大小和视觉清晰度之间提供最佳平衡。

不应该,仅对影响 LCP 的 1-2 张关键首屏图片使用 priority。过度使用会违背懒加载的目的,实际上会因同时加载过多图片而损害性能。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay