本节摘要:图片、字体、favicon 等静态资源怎么放、怎么引用、怎么优化?本节讲清 public/ 目录的约定、next/image 的自动优化能力(尺寸、格式、懒加载)、字体优化(next/font),以及资源组织的最佳实践。
阅读完本节,你应当能够:
纯 React 项目里,图片优化是老大难:不同设备要不同尺寸、要转 WebP 压缩、要懒加载、要防布局偏移。Next.js 的 next/image 把这些全部自动化——你只需要写一个 <Image>,框架处理尺寸、格式、懒加载与缓存。
直觉类比:<Image> 像"智能图片服务员"——你告诉它"这张图在哪、要多大",它自动把图片处理成最合适的尺寸与格式再端上来,还负责"先占好位置防止页面跳动"。
💡 关键直觉:public/ 目录是"根路径映射"——
public/logo.png通过/logo.png访问,不参与构建处理;而next/image处理的是"优化路径"(/_next/image?url=...),两者分工不同。
public/ ├── logo.png → /logo.png ├── favicon.ico → /favicon.ico └── docs/manual.pdf → /docs/manual.pdf
// 直接引用 <img src="/logo.png" alt="Logo" /> // 或 <Image src="/logo.png" alt="Logo" width={120} height={40} />
适用:favicon、PDF、需要固定 URL 的资源。注意:public/ 资源不经过优化,图片类优先用 next/image。
import Image from "next/image"; export default function Avatar() { return ( <Image src="/avatar.png" // 本地或远程 URL alt="用户头像" width={200} // 必填:决定尺寸 height={200} priority // 首屏图用 priority 加快加载 className="rounded-full" /> ); }
自动优化能力:
| 能力 | 说明 |
|---|---|
| 响应式尺寸 | 按设备生成多尺寸,加载最合适的 |
| 格式转换 | 自动转 WebP/AVIF 压缩 |
| 懒加载 | 进入视口才加载(默认) |
| 防 CLS | 占位尺寸,防止布局偏移 |
| 缓存 | CDN 级缓存,重复访问秒开 |
加载外部图片(如 `「相关地址请参见官方文档」
// next.config.ts const nextConfig = { images: { remotePatterns: [ { protocol: "https", hostname: "cdn.example.com" }, { protocol: "https", hostname: "**.example.org" }, ], }, }; export default nextConfig;
不配置会报错(next/image 拒绝未知域名,防滥用)。
// app/layout.tsx import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"] }); export default function RootLayout({ children }) { return ( <html lang="zh-CN" className={inter.className}> <body>{children}</body> </html> ); }
next/font 的价值:自动优化字体加载(自托管、无 CLS、fallback 自动)、支持中文子集化。本地字体用 next/font/local。
app/ ├── icon.png # favicon(自动应用) ├── icon.ico └── apple-icon.png # Apple 设备图标
按约定放 app/ 目录即可,Next.js 自动生成 link 标签。
<Image>(除非极小或需要原始 URL);| 误区 | 现象 | 正解 |
|---|---|---|
| Image 不传 width/height | 报错或布局偏移 | 必填尺寸或用 fill |
| 远程图片报错 | 域名未配置 | 加 remotePatterns |
| 首屏图懒加载 | 首屏白图 | 加 priority |
用了 <img> 而非 Image |
无优化 | 用 next/image |
| public 图片不更新 | 缓存 | 换文件名或清缓存 |
// components/PhotoGrid.tsx import Image from "next/image"; const photos = [ { src: "/photos/1.jpg", alt: "风景 1" }, { src: "/photos/2.jpg", alt: "风景 2" }, ]; export default function PhotoGrid() { return ( <div className="grid grid-cols-2 gap-4"> {photos.map((p) => ( <Image key={p.src} src={p.src} alt={p.alt} width={400} height={300} className="rounded-lg object-cover" /> ))} </div> ); }
打开浏览器开发者工具的 Network 面板:图片以 WebP 格式、合适尺寸加载,滚动时才加载视口内的图——优化是默认行为,不是额外工作。
next/image 的优化管线:请求图片时,按设备宽度生成合适尺寸、转 WebP/AVIF、设置缓存头——浏览器拿到的是"刚好够用"的图片,而不是原图。
| 资源类型 | 处理方式 | 原因 |
|---|---|---|
| 页面图片 | next/image | 自动优化 |
| 背景图 | CSS + 优化后的图 | 或 Image fill |
| 用户上传 | 存对象存储 + CDN | 服务器不放用户文件 |
| 图标 | SVG 内联或 icon 组件 | 矢量、轻量 |
| 文档(PDF) | public/ 或对象存储 | 不需优化 |
| 字体 | next/font | 防布局偏移 |
一句话:图片优化的目标是"用户看到的图,恰好够清晰、尽量小、不跳动"——next/image 把这套工程自动化,你要做的只是"用 Image 而不是 img"、配置好远程域名。
问:public 目录的图片能用 Image 优化吗?
能。Image 的 src 填 /xxx.png(public 路径),会自动优化。区别在于:public 里的原图仍在(可被直接访问),Image 请求的是优化版本。
问:远程图片必须配置域名吗?
必须。出于安全(防开放代理滥用),next/image 拒绝未配置的远程域名。在 next.config 的 images.remotePatterns 里添加。
问:fill 模式怎么用?
容器用相对定位并设尺寸,Image 用 fill 填满容器(配合 object-cover 裁切):
<div className="relative h-64 w-full"> <Image src="/banner.jpg" alt="横幅" fill className="object-cover" /> </div>
问:favicon 怎么改?
把 app/icon.png(或 icon.ico)替换为你自己的图标即可,Next.js 自动应用。尺寸建议 32x32 或 512x512。
静态资源的铁律:图片用 next/image(自动优化),非图片放 public/,远程图配域名。next/image 的尺寸/格式/懒加载/防 CLS 全是默认行为,你要做的只是"用 Image 而不是 img"。字体用 next/font 防布局偏移,favicon 按约定放 app/ 目录。
做一个图片画廊来验证本节知识:准备几张本地图片放 public/photos/,用 next/image 渲染成网格(指定宽高),观察浏览器 Network 面板中图片以 WebP 格式、合适尺寸懒加载。再配置一个远程图片域名(remotePatterns),加载一张外链图片。
进阶练习:给画廊加"首屏图 priority"与"容器 fill 模式"两种形态,对比加载行为;用 next/font/local 加载一个本地字体(如思源黑体子集),观察字体文件大小与布局稳定性。做完后,资源优化的三个核心(图片、域名、字体)就全掌握了。