12k
All articles

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

通过内置组件、自定义加载器和 CDN 集成优化 Next.js 图片,改善 Core Web Vitals,降低 LCP,并消除布局偏移。

OpenReplay Team
OpenReplay Team
如何在 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/image 吗?

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

为什么我的图片在视网膜显示器上模糊?

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

我应该对所有重要图片使用 priority 吗?

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

DevTools for the frontend

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.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.