Image (Legacy)
从 Next.js 13 开始,next/image 组件被重写以提高性能和开发者体验。为了提供向后兼容的升级方案,旧的 next/image 被重命名为 next/legacy/image。
警告:
next/legacy/image已被弃用,将在 Next.js 的未来版本中移除。请改用next/image。
对比
与 next/legacy/image 相比,新的 next/image 组件有以下变化:
- 移除了
<img>周围的<span>包装器,改用原生计算纵横比 - 添加了对标准
style属性的支持- 移除了
layout属性,改用style或className - 移除了
objectFit属性,改用style或className - 移除了
objectPosition属性,改用style或className
- 移除了
- 移除了
IntersectionObserver实现,改用原生懒加载- 移除了
lazyBoundary属性,因为没有原生等效项 - 移除了
lazyRoot属性,因为没有原生等效项
- 移除了
- 移除了
loader配置,改用loader属性 - 将
alt属性从可选改为必需 - 改变了
onLoadingComplete回调,现在接收对<img>元素的引用
必需属性
<Image /> 组件需要以下属性。
src
必须是以下之一:
当使用默认 loader 时,还需要考虑以下关于源图像的事项:
- 当 src 是外部 URL 时,你还必须配置 remotePatterns
- 当 src 是动画图像或不是已知格式(JPEG、PNG、WebP、AVIF、GIF、TIFF)时,图像将按原样提供
- 当 src 是 SVG 格式时,除非启用
unoptimized或dangerouslyAllowSVG,否则将被阻止
width
width 属性可以表示以像素为单位的_渲染_宽度或_原始_宽度,具体取决于 layout 和 sizes 属性。
当使用 layout="intrinsic" 或 layout="fixed" 时,width 属性表示以像素为单位的_渲染_宽度,因此它会影响图像显示的大小。
当使用 layout="responsive" 或 layout="fill" 时,width 属性表示以像素为单位的_原始_宽度,因此它只会影响纵横比。
除了静态导入的图像或使用 layout="fill" 的图像外,width 属性是必需的。
height
height 属性可以表示以像素为单位的_渲染_高度或_原始_高度,具体取决于 layout 和 sizes 属性。
当使用 layout="intrinsic" 或 layout="fixed" 时,height 属性表示以像素为单位的_渲染_高度,因此它会影响图像显示的大小。
当使用 layout="responsive" 或 layout="fill" 时,height 属性表示以像素为单位的_原始_高度,因此它只会影响纵横比。
除了静态导入的图像或使用 layout="fill" 的图像外,height 属性是必需的。
可选属性
除了必需的属性外,<Image /> 组件还接受许多额外属性。本节描述 Image 组件最常用的属性。在高级属性部分可以找到更少使用的属性的详细信息。
layout
随着视口大小变化时图像的布局行为。
layout | 行为 | srcSet | sizes | 是否有包装器和尺寸器 |
|---|---|---|---|---|
intrinsic(默认) | 缩小以适应容器宽度,最大到图像尺寸 | 1x、2x(基于 imageSizes) | N/A | 是 |
fixed | 精确设置为 width 和 height 的大小 | 1x、2x(基于 imageSizes) | N/A | 是 |
responsive | 缩放以适应容器宽度 | 640w、750w、... 2048w、3840w(基于 imageSizes 和 deviceSizes) | 100vw | 是 |
fill | 在 X 和 Y 轴上增长以填充容器 | 640w、750w、... 2048w、3840w(基于 imageSizes 和 deviceSizes) | 100vw | 是 |
- 演示
intrinsic布局(默认)- 当使用
intrinsic时,图像将为较小的视口缩小尺寸,但为较大的视口保持原始尺寸。
- 当使用
- 演示
fixed布局- 当使用
fixed时,图像尺寸不会随着视口变化而改变(无响应性),类似于原生img元素。
- 当使用
- 演示
responsive布局- 当使用
responsive时,图像将为较小的视口缩小尺寸,并为较大的视口放大。 - 确保父元素在其样式表中使用
display: block。
- 当使用
- 演示
fill布局- 当使用
fill时,图像将拉伸宽度和高度以适应父元素的尺寸,前提是父元素是相对定位的。 - 这通常与
objectFit属性配对使用。 - 确保父元素在其样式表中有
position: relative。
- 当使用
- 演示背景图像
loader
用于解析 URL 的自定义函数。将 loader 设置为 Image 组件的属性会覆盖在 next.config.js 的 images 部分中定义的默认 loader。
loader 是一个函数,在给定以下参数的情况下,为图像返回 URL 字符串:
以下是使用自定义 loader 的示例:
import Image from 'next/legacy/image'
const myLoader = ({ src, width, quality }) => {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
const MyImage = (props) => {
return (
<Image
loader={myLoader}
src="me.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}sizes
一个字符串,提供有关图像在不同断点处宽度的信息。对于使用 layout="responsive" 或 layout="fill" 的图像,sizes 的值将极大地影响性能。对于使用 layout="intrinsic" 或 layout="fixed" 的图像,它将被忽略。
sizes 属性有两个与图像性能相关的重要用途:
首先,浏览器使用 sizes 的值来确定从 next/legacy/image 自动生成的源集中下载哪个尺寸的图像。当浏览器进行选择时,它还不知道页面上图像的大小,因此它会选择与视口大小相同或更大的图像。sizes 属性允许你告诉浏览器图像实际上会小于全屏。如果你不指定 sizes 值,将使用默认值 100vw(全屏宽度)。
其次,sizes 值会被解析并用于修剪自动创建的源集中的值。如果 sizes 属性包含表示视口宽度百分比的尺寸(如 50vw),则源集会被修剪以不包含任何永远不需要的过小值。
例如,如果你知道你的样式会导致图像在移动设备上全宽,在平板电脑上为 2 列布局,在桌面显示器上为 3 列布局,你应该包含如下的 sizes 属性:
import Image from 'next/legacy/image'
const Example = () => (
<div className="grid-element">
<Image
src="/example.png"
layout="fill"
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw"
/>
</div>
)这个示例 sizes 可能会对性能指标产生巨大影响。如果没有 33vw sizes,从服务器选择的图像会比需要的宽 3 倍。因为文件大小与宽度的平方成正比,如果没有 sizes,用户将下载比必要大 9 倍的图像。
了解更多关于 srcset 和 sizes 的信息:
quality
优化图像的质量,介于 1 和 100 之间的整数,其中 100 是最佳质量。默认为 75。
priority
当为 true 时,图像将被视为高优先级并预加载。对于使用 priority 的图像,懒加载会自动禁用。
你应该对任何被检测为最大内容绘制(LCP)元素的图像使用 priority 属性。拥有多个优先级图像可能是合适的,因为不同的图像可能是不同视口大小的 LCP 元素。
只应在图像在首屏可见时使用。默认为 false。
placeholder
图像加载时使用的占位符。可能的值是 blur 或 empty。默认为 empty。
当为 blur 时,blurDataURL 属性将用作占位符。如果 src 是来自静态导入的对象,且导入的图像是 .jpg、.png、.webp 或 .avif,则 blurDataURL 将自动填充。
对于动态图像,你必须提供 blurDataURL 属性。Plaiceholder 等解决方案可以帮助生成 base64。
当为 empty 时,图像加载时将没有占位符,只有空白空间。
试试看:
高级属性
在某些情况下,你可能需要更高级的用法。<Image /> 组件可选地接受以下高级属性。
style
允许传递 CSS 样式到底层图像元素。
请注意,所有 layout 模式都会将自己的样式应用于图像元素,这些自动样式优先于 style 属性。
还要记住,必需的 width 和 height 属性可能会与你的样式交互。如果你使用样式修改图像的 width,你还必须设置 height="auto" 样式,否则你的图像会变形。
objectFit
定义使用 layout="fill" 时图像如何适应其父容器。
此值传递给 src 图像的 object-fit CSS 属性。
objectPosition
定义使用 layout="fill" 时图像如何在其父元素中定位。
此值传递给应用于图像的 object-position CSS 属性。
onLoadingComplete
图像完全加载且占位符已被移除后调用的回调函数。
onLoadingComplete 函数接受一个参数,一个具有以下属性的对象:
loading
图像的加载行为。默认为 lazy。
当为 lazy 时,延迟加载图像,直到它到达与视口的计算距离。
当为 eager 时,立即加载图像。
blurDataURL
一个 Data URL,用作 src 图像成功加载前的占位符图像。仅在与 placeholder="blur" 结合使用时生效。
必须是 base64 编码的图像。它会被放大和模糊,因此建议使用非常小的图像(10px 或更小)。包含较大的图像作为占位符可能会损害应用程序的性能。
试试看:
你还可以生成纯色 Data URL 以匹配图像。
lazyBoundary
一个字符串(语法类似于 margin 属性),用作用于检测视口与图像交集并触发懒加载的边界框。默认为 "200px"。
如果图像嵌套在根文档以外的可滚动父元素中,你还需要设置 lazyRoot 属性。
lazyRoot
一个指向可滚动父元素的 React Ref。默认为 null(文档视口)。
Ref 必须指向 DOM 元素或转发 Ref 到底层 DOM 元素的 React 组件。
指向 DOM 元素的示例
import Image from 'next/legacy/image'
import React from 'react'
const Example = () => {
const lazyRoot = React.useRef(null)
return (
<div ref={lazyRoot} style={{ overflowX: 'scroll', width: '500px' }}>
<Image lazyRoot={lazyRoot} src="/one.jpg" width="500" height="500" />
<Image lazyRoot={lazyRoot} src="/two.jpg" width="500" height="500" />
</div>
)
}指向 React 组件的示例
import Image from 'next/legacy/image'
import React from 'react'
const Container = React.forwardRef((props, ref) => {
return (
<div ref={ref} style={{ overflowX: 'scroll', width: '500px' }}>
{props.children}
</div>
)
})
const Example = () => {
const lazyRoot = React.useRef(null)
return (
<Container ref={lazyRoot}>
<Image lazyRoot={lazyRoot} src="/one.jpg" width="500" height="500" />
<Image lazyRoot={lazyRoot} src="/two.jpg" width="500" height="500" />
</Container>
)
}unoptimized
当为 true 时,源图像将按原样从 src 提供,而不改变质量、大小或格式。默认为 false。
这对于不受益于优化的图像很有用,例如小图像(小于 1KB)、矢量图像(SVG)或动画图像(GIF)。
import Image from 'next/image'
const UnoptimizedImage = (props) => {
return <Image {...props} unoptimized />
}从 Next.js 12.3.0 开始,可以通过使用以下配置更新 next.config.js 来将此属性分配给所有图像:
module.exports = {
images: {
unoptimized: true,
},
}其他属性
<Image /> 组件上的其他属性将传递给底层 img 元素,但以下除外:
srcSet。请改用设备尺寸。ref。请改用onLoadingComplete。decoding。它始终为"async"。
配置选项
远程模式
为了保护你的应用程序免受恶意用户的攻击,需要进行配置才能使用外部图像。这确保只有来自你帐户的外部图像可以从 Next.js 图像优化 API 提供服务。这些外部图像可以使用 next.config.js 文件中的 remotePatterns 属性进行配置,如下所示:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/account123/**',
search: '',
},
],
},
}值得注意的是:上面的示例将确保
next/legacy/image的src属性必须以https://example.com/account123/开头,并且不能有查询字符串。任何其他协议、主机名、端口或不匹配的路径都将响应 400 Bad Request。
以下是 next.config.js 文件中 remotePatterns 属性在 hostname 中使用通配符模式的示例:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
port: '',
search: '',
},
],
},
}值得注意的是:上面的示例将确保
next/legacy/image的src属性必须以https://img1.example.com或https://me.avatar.example.com或任意数量的子域开头。它不能有端口或查询字符串。任何其他协议或不匹配的主机名都将响应 400 Bad Request。
通配符模式可用于 pathname 和 hostname,并具有以下语法:
*匹配单个路径段或子域**匹配末尾的任意数量的路径段或开头的子域
** 语法在模式中间不起作用。
值得注意的是:当省略
protocol、port、pathname或search时,则隐含通配符**。不建议这样做,因为它可能允许恶意行为者优化你不打算优化的 url。
以下是 next.config.js 文件中使用 search 的 remotePatterns 属性的示例:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'assets.example.com',
search: '?v=1727111025337',
},
],
},
}值得注意的是:上面的示例将确保
next/legacy/image的src属性必须以https://assets.example.com开头,并且必须具有确切的查询字符串?v=1727111025337。任何其他协议或查询字符串都将响应 400 Bad Request。
域
警告:自 Next.js 14 起已弃用,改用严格的
remotePatterns以保护你的应用程序免受恶意用户的攻击。仅在你拥有从域提供的所有内容时才使用domains。
与 remotePatterns 类似,domains 配置可用于提供外部图像的允许主机名列表。
但是,domains 配置不支持通配符模式匹配,并且无法限制协议、端口或路径名。
以下是 next.config.js 文件中 domains 属性的示例:
module.exports = {
images: {
domains: ['assets.acme.com'],
},
}Loader 配置
如果你想使用云提供商来优化图像,而不是使用 Next.js 内置的图像优化 API,你可以在 next.config.js 文件中配置 loader 和 path 前缀。这允许你为图像 src 使用相对 URL,并自动为你的提供商生成正确的绝对 URL。
module.exports = {
images: {
loader: 'imgix',
path: 'https://example.com/myaccount/',
},
}自定义内置图像路径
如果你想更改或为内置 Next.js 图像优化添加前缀,可以使用 path 属性来实现。path 的默认值是 /_next/image。
module.exports = {
images: {
path: '/my-prefix/_next/image',
},
}内置 Loader
包含以下图像优化云提供商:
- 默认:使用
next dev、next start或自定义服务器时自动工作 - Vercel:在 Vercel 上部署时自动工作,无需配置。了解更多
- Imgix:
loader: 'imgix' - Cloudinary:
loader: 'cloudinary' - Akamai:
loader: 'akamai' - 自定义:
loader: 'custom'通过在next/legacy/image组件上实现loader属性来使用自定义云提供商
如果你需要不同的提供商,可以在 next/legacy/image 中使用 loader 属性。
使用
output: 'export'时,无法在构建时优化图像,只能按需优化。要在output: 'export'中使用next/legacy/image,你需要使用与默认不同的 loader。在讨论中阅读更多内容。
高级
以下配置适用于高级用例,通常不是必需的。如果你选择配置以下属性,你将在未来更新中覆盖对 Next.js 默认值的任何更改。
设备尺寸
如果你知道用户的预期设备宽度,可以使用 next.config.js 中的 deviceSizes 属性指定设备宽度断点列表。当 next/legacy/image 组件使用 layout="responsive" 或 layout="fill" 时,会使用这些宽度来确保为用户设备提供正确的图像。
如果未提供配置,则使用以下默认值。
module.exports = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
}图像尺寸
你可以使用 next.config.js 文件中的 images.imageSizes 属性指定图像宽度列表。这些宽度与设备尺寸数组连接,形成用于生成图像 srcset 的完整尺寸数组。
有两个单独列表的原因是 imageSizes 仅用于提供 sizes 属性的图像,这表示图像小于屏幕的全宽。因此,imageSizes 中的尺寸都应小于 deviceSizes 中的最小尺寸。
如果未提供配置,则使用以下默认值。
module.exports = {
images: {
imageSizes: [32, 48, 64, 96, 128, 256, 384],
},
}可接受的格式
默认图像优化 API 将通过请求的 Accept 头自动检测浏览器支持的图像格式,以确定最佳输出格式。
如果 Accept 头匹配多个已配置的格式,则使用数组中的第一个匹配项。因此,数组顺序很重要。如果没有匹配项(或源图像是动画的),图像优化 API 将回退到原始图像的格式。
如果未提供配置,则使用以下默认值。
module.exports = {
images: {
formats: ['image/webp'],
},
}你可以启用 AVIF 支持,如果浏览器不支持 AVIF,它将回退到 src 图像的原始格式:
module.exports = {
images: {
formats: ['image/avif'],
},
}值得注意的是:
- 我们仍然建议在大多数用例中使用 WebP。
- AVIF 通常需要 50% 的编码时间,但压缩比 WebP 小 20%。这意味着第一次请求图像时,通常会更慢,然后缓存的后续请求会更快。
- 如果你使用 Next.js 前面的代理/CDN 自托管,则必须配置代理以转发
Accept头。
缓存行为
以下描述默认 loader 的缓存算法。对于所有其他 loader,请参阅你的云提供商的文档。
图像在请求时动态优化,并存储在 <distDir>/cache/images 目录中。优化的图像文件将在后续请求中提供,直到到达过期时间。当发出与缓存但已过期的文件匹配的请求时,过期的图像会立即过时提供。然后图像在后台再次优化(也称为重新验证)并以新的过期日期保存到缓存中。
可以通过读取 x-nextjs-cache(在 Vercel 上部署时为 x-vercel-cache)响应头的值来确定图像的缓存状态。可能的值如下:
MISS- 路径不在缓存中(最多发生一次,在第一次访问时)STALE- 路径在缓存中但超过了重新验证时间,因此它将在后台更新HIT- 路径在缓存中且未超过重新验证时间
过期(或者说最大年龄)由 minimumCacheTTL 配置或上游图像 Cache-Control 头定义,以较大者为准。具体来说,使用 Cache-Control 头的 max-age 值。如果同时找到 s-maxage 和 max-age,则优先使用 s-maxage。max-age 也会传递给任何下游客户端,包括 CDN 和浏览器。
- 当上游图像不包含
Cache-Control头或值非常低时,你可以配置minimumCacheTTL以增加缓存持续时间。 - 你可以配置
deviceSizes和imageSizes以减少可能生成的图像总数。 - 你可以配置格式以禁用多种格式,改用单一图像格式。
最小缓存 TTL
你可以为缓存的优化图像配置生存时间(TTL)(以秒为单位)。在许多情况下,最好使用静态图像导入,它会自动对文件内容进行哈希处理,并使用 immutable 的 Cache-Control 头永久缓存图像。
如果未提供配置,则使用以下默认值。
module.exports = {
images: {
minimumCacheTTL: 14400, // 4 小时
},
}你可以增加 TTL 以减少重新验证的次数并可能降低成本:
module.exports = {
images: {
minimumCacheTTL: 2678400, // 31 天
},
}优化图像的过期(或者说最大年龄)由 minimumCacheTTL 或上游图像 Cache-Control 头定义,以较大者为准。
如果你需要更改每个图像的缓存行为,可以配置 headers 以在上游图像上设置 Cache-Control 头(例如 /some-asset.jpg,而不是 /_next/image 本身)。
目前没有使缓存失效的机制,因此最好保持 minimumCacheTTL 较低。否则,你可能需要手动更改 src 属性或删除 <distDir>/cache/images。
禁用静态导入
默认行为允许你导入静态文件,例如 import icon from './icon.png',然后将其传递给 src 属性。
在某些情况下,如果此功能与期望导入行为不同的其他插件冲突,你可能希望禁用此功能。
你可以在 next.config.js 中禁用静态图像导入:
module.exports = {
images: {
disableStaticImages: true,
},
}危险地允许 SVG
出于几个原因,默认 loader 不优化 SVG 图像。首先,SVG 是矢量格式,意味着它可以无损调整大小。其次,SVG 具有许多与 HTML/CSS 相同的功能,如果没有适当的内容安全策略(CSP)头,可能会导致漏洞。
因此,当 src 属性已知为 SVG 时,我们建议使用 unoptimized 属性。当 src 以 ".svg" 结尾时,这会自动发生。
但是,如果你需要使用默认图像优化 API 提供 SVG 图像,可以在 next.config.js 中设置 dangerouslyAllowSVG:
module.exports = {
images: {
dangerouslyAllowSVG: true,
contentDispositionType: 'attachment',
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
}此外,强烈建议同时设置 contentDispositionType 以强制浏览器下载图像,以及 contentSecurityPolicy 以防止嵌入图像中的脚本执行。
contentDispositionType
默认 loader 为 Content-Disposition 头设置 attachment 以提供额外保护,因为 API 可以提供任意远程图像。
默认值是 attachment,它会强制浏览器在直接访问时下载图像。这在 dangerouslyAllowSVG 为 true 时尤其重要。
你可以选择配置 inline 以允许浏览器在直接访问时渲染图像,而无需下载。
module.exports = {
images: {
contentDispositionType: 'inline',
},
}动画图像
默认 loader 将自动绕过动画图像的图像优化,并按原样提供图像。
动画文件的自动检测是尽力而为的,支持 GIF、APNG 和 WebP。如果你想显式绕过给定动画图像的图像优化,请使用 unoptimized 属性。
版本历史
| 版本 | 变更 |
|---|---|
v16.0.0 | next/legacy/image 已被弃用,将在 Next.js 的未来版本中移除。请改用 next/image。 |
v13.0.0 | next/image 重命名为 next/legacy/image |