图片优化
深入理解 Next.js 图片优化机制,包括 Image 组件、本地/远程图片、尺寸优化、占位符、样式和配置
概述
Next.js <Image> 组件扩展了 HTML <img> 元素,提供以下功能:
- 尺寸优化:自动为每个设备提供正确尺寸的图片,使用 WebP 等现代图片格式
- 视觉稳定性:在图片加载时自动防止布局偏移
- 更快的页面加载:使用原生浏览器懒加载,仅在图片进入视口时加载,可选模糊占位符
- 资源灵活性:按需调整图片大小,即使是存储在远程服务器上的图片
基本使用
从 next/image 导入并在组件中渲染:
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}本地图片
静态文件(如图片和字体)可以存储在根目录下的 public 文件夹中。public 内的文件可以从基础 URL(/)开始引用。
使用本地图片
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}静态导入
import Image from 'next/image'
import profilePic from './profile.png'
export default function Page() {
return (
<Image
src={profilePic}
alt="Picture of the author"
// width 和 height 会自动从导入的图片推断
/>
)
}使用静态导入时,Next.js 会自动确定图片的 width 和 height,用于防止图片加载时的布局偏移。
远程图片
要使用远程图片,src 属性应该是一个 URL 字符串。
import Image from 'next/image'
export default function Page() {
return (
<Image
src="https://s3.amazonaws.com/my-bucket/profile.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}配置远程模式
由于 Next.js 在构建过程中无法访问远程文件,你需要手动提供 width、height 和可选的 blurDataURL 属性。
要安全地允许来自远程服务器的图片,需要在 next.config.js 中定义支持的 URL 模式列表:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 's3.amazonaws.com',
port: '',
pathname: '/my-bucket/**',
search: '',
},
],
},
}
export default config使用多个远程模式
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
{
protocol: 'https',
hostname: 'cdn.example.com',
},
],
},
}
export default config必需属性
src
图片的源,可以是以下之一:
- 内部路径字符串:
/profile.png - 绝对外部 URL:
https://example.com/profile.png(必须配置remotePatterns) - 静态导入:
import profile from './profile.png'
alt
alt 属性用于为屏幕阅读器和搜索引擎描述图片。如果图片被禁用或加载时发生错误,它也是后备文本。
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
/>width 和 height
width 和 height 属性用于推断图片的正确宽高比并避免图片加载时的布局偏移。
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
/>对于静态导入的图片,这些值会自动推断。对于远程图片,必须手动提供。
可选属性
fill
布尔值,使图片填充父元素的大小。父元素必须设置 position: relative、position: fixed 或 position: absolute。
import Image from 'next/image'
export default function Page() {
return (
<div style={{ position: 'relative', width: '300px', height: '500px' }}>
<Image
src="/profile.png"
alt="Picture of the author"
fill
style={{ objectFit: 'cover' }}
/>
</div>
)
}sizes
定义图片在不同断点的大小,用于响应式图片。
<Image
src="/profile.png"
alt="Picture of the author"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>quality
优化图片的质量,介于 1 和 100 之间的整数,默认为 75。
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
quality={90}
/>priority
布尔值,当为 true 时,图片将被视为高优先级并预加载。对于 LCP(Largest Contentful Paint)图片应该使用此属性。
<Image
src="/hero.png"
alt="Hero image"
width={1200}
height={600}
priority
/>placeholder
图片加载时使用的占位符。可能的值:
blur:使用blurDataURL作为占位符empty(默认):图片加载时没有占位符
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>blurDataURL
用作占位符图片的 Data URL。仅在与 placeholder="blur" 结合使用时生效。
对于静态导入的图片,会自动生成。对于远程图片,必须手动提供。
<Image
src="https://example.com/profile.png"
alt="Picture of the author"
width={500}
height={500}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAhEAACAQMDBQAAAAAAAAAAAAABAgMABAUGIWEREiMxUf/EABUBAQEAAAAAAAAAAAAAAAAAAAMF/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECEgMRkf/aAAwDAQACEQMRAD8AltJagyeH0AthI5xdrLcNM91BF5pX2HaH9bcfaSXWGaRmknyJckliyjqTzSlT54b6bk+h0R//2Q=="
/>loading
图片的加载行为。可能的值:
lazy(默认):延迟加载图片,直到它接近视口eager:立即加载图片
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
loading="eager"
/>unoptimized
布尔值,当为 true 时,源图片将按原样提供,不改变质量、大小或格式。默认为 false。
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
unoptimized
/>样式
使用 className
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
className="rounded-lg shadow-lg"
/>
)
}使用 style
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
style={{ borderRadius: '8px', boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)' }}
/>
)
}使用 CSS Modules
.image {
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}import Image from 'next/image'
import styles from './page.module.css'
export default function Page() {
return (
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
className={styles.image}
/>
)
}响应式图片
使用 fill 和 sizes
import Image from 'next/image'
export default function Page() {
return (
<div className="container">
<Image
src="/hero.png"
alt="Hero image"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ objectFit: 'cover' }}
/>
</div>
)
}.container {
position: relative;
width: 100%;
height: 400px;
}响应式宽度和高度
import Image from 'next/image'
export default function Page() {
return (
<div className="image-container">
<Image
src="/profile.png"
alt="Picture of the author"
width={500}
height={500}
sizes="100vw"
style={{
width: '100%',
height: 'auto',
}}
/>
</div>
)
}配置选项
remotePatterns
配置允许的远程图片 URL 模式:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/images/**',
search: '',
},
],
},
}
export default configformats
配置图片优化 API 支持的图片格式:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
formats: ['image/avif', 'image/webp'],
},
}
export default configdeviceSizes
定义设备宽度断点:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
}
export default configimageSizes
定义图片宽度断点:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
}
export default configminimumCacheTTL
配置优化图片的最小缓存 TTL(以秒为单位):
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
minimumCacheTTL: 60,
},
}
export default configdangerouslyAllowSVG
允许 SVG 图片优化:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
dangerouslyAllowSVG: true,
contentDispositionType: 'attachment',
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
}
export default config自定义加载器
配置全局加载器
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
loader: 'custom',
loaderFile: './my-loader.ts',
},
}
export default config创建自定义加载器
export default function myImageLoader({
src,
width,
quality,
}: {
src: string
width: number
quality?: number
}) {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}使用组件级加载器
import Image from 'next/image'
const myLoader = ({ src, width, quality }: {
src: string
width: number
quality?: number
}) => {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
export default function Page() {
return (
<Image
loader={myLoader}
src="profile.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}高级用法
背景图片
import Image from 'next/image'
export default function Page() {
return (
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/background.jpg"
alt="Background"
fill
style={{ objectFit: 'cover', zIndex: -1 }}
/>
<div style={{ position: 'relative', zIndex: 1, padding: '20px' }}>
<h1>Content over background</h1>
</div>
</div>
)
}图片画廊
import Image from 'next/image'
const images = [
{ src: '/gallery/1.jpg', alt: 'Image 1' },
{ src: '/gallery/2.jpg', alt: 'Image 2' },
{ src: '/gallery/3.jpg', alt: 'Image 3' },
]
export default function Gallery() {
return (
<div className="grid grid-cols-3 gap-4">
{images.map((image, index) => (
<div key={index} className="relative aspect-square">
<Image
src={image.src}
alt={image.alt}
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ objectFit: 'cover' }}
/>
</div>
))}
</div>
)
}带占位符的图片
import Image from 'next/image'
import profilePic from './profile.jpg'
export default function Page() {
return (
<Image
src={profilePic}
alt="Picture of the author"
placeholder="blur"
// blurDataURL 会自动从静态导入生成
/>
)
}动态模糊占位符
import Image from 'next/image'
async function getBase64(imageUrl: string) {
const response = await fetch(imageUrl)
const buffer = await response.arrayBuffer()
const base64 = Buffer.from(buffer).toString('base64')
return `data:image/jpeg;base64,${base64}`
}
export default async function Page() {
const blurDataURL = await getBase64('https://example.com/profile.jpg')
return (
<Image
src="https://example.com/profile.jpg"
alt="Picture of the author"
width={500}
height={500}
placeholder="blur"
blurDataURL={blurDataURL}
/>
)
}性能优化
优先加载关键图片
对于 LCP(Largest Contentful Paint)图片使用 priority:
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority
/>
)
}懒加载非关键图片
默认情况下,图片会懒加载。对于首屏以下的图片,保持默认行为:
import Image from 'next/image'
export default function Page() {
return (
<div>
<Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority />
{/* 这些图片会懒加载 */}
<Image src="/image1.jpg" alt="Image 1" width={500} height={500} />
<Image src="/image2.jpg" alt="Image 2" width={500} height={500} />
</div>
)
}使用正确的图片格式
Next.js 会自动选择最佳格式(WebP、AVIF)。确保配置支持现代格式:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
formats: ['image/avif', 'image/webp'],
},
}
export default config最佳实践
1. 始终提供 alt 文本
// 好的做法
<Image src="/profile.png" alt="John Doe's profile picture" width={500} height={500} />
// 不好的做法
<Image src="/profile.png" alt="" width={500} height={500} />2. 为 LCP 图片使用 priority
export default function Page() {
return (
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // 对于首屏最大的图片
/>
)
}3. 使用适当的尺寸
// 好的做法 - 提供实际显示尺寸
<Image src="/profile.png" alt="Profile" width={200} height={200} />
// 不好的做法 - 加载过大的图片
<Image src="/profile.png" alt="Profile" width={2000} height={2000} />4. 使用 fill 进行响应式布局
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/hero.jpg"
alt="Hero"
fill
sizes="100vw"
style={{ objectFit: 'cover' }}
/>
</div>5. 配置远程模式
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
pathname: '/images/**',
},
],
},
}
export default config6. 使用占位符改善 UX
<Image
src="/profile.png"
alt="Profile"
width={500}
height={500}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>常见问题
布局偏移
始终提供 width 和 height 或使用 fill 属性:
// 方案 1:提供尺寸
<Image src="/profile.png" alt="Profile" width={500} height={500} />
// 方案 2:使用 fill
<div style={{ position: 'relative', width: '500px', height: '500px' }}>
<Image src="/profile.png" alt="Profile" fill />
</div>远程图片不显示
确保在 next.config.ts 中配置了 remotePatterns:
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}
export default config图片质量低
调整 quality 属性:
<Image
src="/profile.png"
alt="Profile"
width={500}
height={500}
quality={90} // 默认是 75
/>总结
Next.js Image 组件提供了强大的图片优化功能:
- 自动优化:自动选择最佳格式(WebP、AVIF)和尺寸
- 懒加载:默认懒加载,提高性能
- 占位符:支持模糊占位符,改善用户体验
- 响应式:使用
fill和sizes实现响应式图片 - 远程图片:支持远程图片,需配置
remotePatterns - 性能优化:使用
priority预加载关键图片 - 灵活配置:支持自定义加载器和多种配置选项
通过合理使用 Image 组件和配置选项,可以显著提升应用的性能和用户体验。
上次更新于