Skip to content

Next.js 图像优化

概述

Next.js 提供了强大的图像优化功能,通过内置的 Image 组件自动优化图像,提升网站性能和用户体验。

🎯 为什么需要图像优化?

图像对性能的影响

javascript
// 传统 HTML 图像标签的问题
<img src="/large-image.jpg" alt="大图" />
// ❌ 不会自动优化
// ❌ 不会响应式调整
// ❌ 可能导致布局偏移
// ❌ 加载速度慢

Next.js Image 组件的优势

  • 自动优化:自动转换为现代格式(WebP、AVIF)
  • 响应式:根据设备自动调整大小
  • 懒加载:视口外的图像延迟加载
  • 防止布局偏移:预留空间避免 CLS
  • 按需优化:首次请求时优化,然后缓存

📦 Image 组件基础

基本使用

jsx
import Image from 'next/image';

export default function ProfilePage() {
  return (
    <div>
      <h1>用户资料</h1>
      
      {/* 本地图像 */}
      <Image
        src="/profile.jpg"
        alt="用户头像"
        width={500}
        height={500}
      />
      
      {/* 远程图像 */}
      <Image
        src="https://example.com/photo.jpg"
        alt="照片"
        width={800}
        height={600}
      />
    </div>
  );
}

必需属性

jsx
function ImageExample() {
  return (
    <Image
      src="/image.jpg"        // 图像路径(必需)
      alt="描述文本"           // 替代文本(必需)
      width={800}             // 宽度(必需,除非 fill)
      height={600}            // 高度(必需,除非 fill)
    />
  );
}

🖼️ 本地图像

导入本地图像

jsx
import Image from 'next/image';
import profilePic from '../public/profile.jpg';

export default function Profile() {
  return (
    <div>
      {/* 自动获取宽高 */}
      <Image
        src={profilePic}
        alt="用户头像"
        placeholder="blur" // 自动模糊占位符
      />
    </div>
  );
}

静态导入的优势

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

// ✅ 自动获取尺寸
// ✅ 自动生成模糊占位符
// ✅ 防止布局偏移

export default function Hero() {
  return (
    <Image
      src={heroImage}
      alt="英雄图"
      priority // 优先加载
    />
  );
}

🌐 远程图像

配置远程图像域名

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

使用远程图像

jsx
import Image from 'next/image';

export default function Gallery() {
  const images = [
    'https://example.com/images/photo1.jpg',
    'https://example.com/images/photo2.jpg',
    'https://example.com/images/photo3.jpg',
  ];
  
  return (
    <div className="gallery">
      {images.map((src, index) => (
        <Image
          key={index}
          src={src}
          alt={`照片 ${index + 1}`}
          width={400}
          height={300}
        />
      ))}
    </div>
  );
}

🎨 响应式图像

使用 fill 属性

jsx
import Image from 'next/image';

export default function ResponsiveImage() {
  return (
    <div style={{ position: 'relative', width: '100%', height: '400px' }}>
      <Image
        src="/banner.jpg"
        alt="横幅"
        fill
        style={{ objectFit: 'cover' }}
      />
    </div>
  );
}

sizes 属性优化

jsx
export default function ResponsiveGallery() {
  return (
    <div className="container">
      <Image
        src="/photo.jpg"
        alt="照片"
        width={800}
        height={600}
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
      />
    </div>
  );
}

⚡ 性能优化

优先加载关键图像

jsx
export default function HomePage() {
  return (
    <div>
      {/* 首屏图像 - 优先加载 */}
      <Image
        src="/hero.jpg"
        alt="英雄图"
        width={1200}
        height={600}
        priority
      />
      
      {/* 其他图像 - 懒加载 */}
      <Image
        src="/content.jpg"
        alt="内容图"
        width={800}
        height={400}
      />
    </div>
  );
}

占位符策略

jsx
import Image from 'next/image';

export default function PlaceholderExamples() {
  return (
    <div>
      {/* 模糊占位符 */}
      <Image
        src="/photo1.jpg"
        alt="照片1"
        width={500}
        height={500}
        placeholder="blur"
        blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
      />
      
      {/* 空占位符 */}
      <Image
        src="/photo2.jpg"
        alt="照片2"
        width={500}
        height={500}
        placeholder="empty"
      />
    </div>
  );
}

质量控制

jsx
export default function QualityControl() {
  return (
    <div>
      {/* 高质量(默认 75) */}
      <Image
        src="/high-quality.jpg"
        alt="高质量"
        width={800}
        height={600}
        quality={90}
      />
      
      {/* 缩略图 - 较低质量 */}
      <Image
        src="/thumbnail.jpg"
        alt="缩略图"
        width={200}
        height={150}
        quality={60}
      />
    </div>
  );
}

🔧 高级配置

自定义加载器

javascript
// next.config.js
module.exports = {
  images: {
    loader: 'custom',
    loaderFile: './my-loader.js',
  },
};
javascript
// my-loader.js
export default function myImageLoader({ src, width, quality }) {
  return `https://cdn.example.com/${src}?w=${width}&q=${quality || 75}`;
}

图像格式配置

javascript
// next.config.js
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
};

🎯 实战示例

图片画廊

jsx
'use client';

import { useState } from 'react';
import Image from 'next/image';

export default function ImageGallery() {
  const [selectedImage, setSelectedImage] = useState(null);
  
  const images = [
    { id: 1, src: '/gallery/1.jpg', alt: '图片1' },
    { id: 2, src: '/gallery/2.jpg', alt: '图片2' },
    { id: 3, src: '/gallery/3.jpg', alt: '图片3' },
  ];
  
  return (
    <div>
      <div className="grid grid-cols-3 gap-4">
        {images.map((image) => (
          <div
            key={image.id}
            className="cursor-pointer"
            onClick={() => setSelectedImage(image)}
          >
            <Image
              src={image.src}
              alt={image.alt}
              width={300}
              height={200}
              className="rounded-lg hover:opacity-80"
            />
          </div>
        ))}
      </div>
      
      {selectedImage && (
        <div className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center">
          <div className="relative w-full max-w-4xl">
            <Image
              src={selectedImage.src}
              alt={selectedImage.alt}
              width={1200}
              height={800}
              className="rounded-lg"
            />
            <button
              onClick={() => setSelectedImage(null)}
              className="absolute top-4 right-4 text-white"
            >
              关闭
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

背景图像

jsx
import Image from 'next/image';

export default function HeroSection() {
  return (
    <div className="relative h-screen">
      <Image
        src="/hero-bg.jpg"
        alt="背景"
        fill
        style={{ objectFit: 'cover' }}
        priority
      />
      <div className="relative z-10 flex items-center justify-center h-full">
        <h1 className="text-white text-6xl font-bold">
          欢迎来到我们的网站
        </h1>
      </div>
    </div>
  );
}

📝 最佳实践

1. 始终提供 alt 文本

jsx
// ✅ 好的做法
<Image src="/photo.jpg" alt="日落时的海滩" width={800} height={600} />

// ❌ 不好的做法
<Image src="/photo.jpg" alt="" width={800} height={600} />

2. 为首屏图像设置 priority

jsx
export default function HomePage() {
  return (
    <div>
      <Image
        src="/hero.jpg"
        alt="英雄图"
        width={1200}
        height={600}
        priority // 首屏图像
      />
    </div>
  );
}

3. 使用适当的尺寸

jsx
// ✅ 根据实际显示尺寸设置
<Image src="/thumb.jpg" alt="缩略图" width={200} height={150} />

// ❌ 避免过大的尺寸
<Image src="/thumb.jpg" alt="缩略图" width={2000} height={1500} />

4. 配置远程图像域名

javascript
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**.example.com', // 支持子域名
      },
    ],
  },
};

📊 性能监控

使用 Next.js Analytics

jsx
// app/layout.js
import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}

📝 本章小结

Next.js 的图像优化功能通过 Image 组件提供了强大的性能优化能力,包括自动格式转换、响应式调整、懒加载等特性。

关键要点

  • ✅ 使用 Image 组件替代 img 标签
  • ✅ 为远程图像配置域名白名单
  • ✅ 首屏图像使用 priority 属性
  • ✅ 使用 fill 属性实现响应式布局
  • ✅ 提供有意义的 alt 文本
  • ✅ 根据实际需求调整质量参数

下一步

在下一章中,我们将学习 Next.js 的字体优化功能。


继续学习下一章 - Next.js 字体优化