要想获得这种魔力,只需将以下代码添加到页面:
import Image from 'next/image';
export default function Page() {
return (
);
}
不过,就像其他任何魔法一样,只有打好坚实的基础,才能熟练的运用自如。
在本文中,我们将探讨Next Image的工作原理,并澄清一些常见误解。
核心架构
next/image的底层架构主要由三个组件组成:
- React Next Image组件
- Image API
- Image优化器
图片
React组件
该组件的主要功能是根据提供的属性生成正确的HTML图像输出,并构造要在srcset和src属性中填充的多个URL。
下面是Next Image组件的示例输出:
生成的URL如下:
/_next/image?url=/images/example.jpg&w=640&q=75
这样编码的URL接受两个参数:w(宽度)和q(质量)。我们发现没有h(高度)属性,这个我们稍后讨论。
Image API
Next Image API用作图像代理,类似于IPX。它执行以下任务:
- 接受图像URL、宽度和质量
- 验证参数
- 确定缓存控制策略
- 处理图像
- 以用户浏览器支持的格式提供图像
Image优化器
Next Image根据特定条件使用不同的图像优化库:Sharp或Squoosh。
Sharp是一个快速高效的图像优化node.js模块,利用原生的libvips库。
Squoosh是一个完全基于节点的图像优化解决方案。有点慢,但不需要在计算机上安装任何其他库。
因此,一般Sharp用于生产环境,而在本地环境中默认使用Squoosh。
p.s.我建议在本地环境中也使用Sharp。虽然Sharp和Squoosh优化图像的方式非常相似,但与Squoosh相比,Sharp的压缩算法会导致颜色下降。这可能会导致生产环境和本地环境之间视觉行为的差异,尤其是在尝试将图像的背景颜色与页面背景匹配时。
结果
了解了next/image背后的主要架构后,让我们一起辨别一些常见的误解,以便更有效地利用它。
next/image不裁剪
开发人员中有个常见的误解是next/image可以裁剪图像。之所以会出现这种混淆,是因为宽度、高度和填充属性可以传递给组件,从而给人一种图像已被裁剪的印象。
实际上,情况并非如此。
Next Image组件主要将宽度和高度用来分配给img标记,以防止布局偏移。
图片
正如之前所说,Image API不接受高度参数,这意味着目前无法更改原始图像的纵横比。
如果不使用fill属性,则在宽度-高度不匹配的情况下,图像只会拉伸或收缩。
但是,如果你使用的是TailwindCSS,由于默认全局CSS规则,它的行为会有所不同:
img,
video {
max-width: 100%;
height: auto;
}
这使得布局偏移问题更难检测。
显示的图像宽度≠加载的图像宽度
另一个潜在的混淆点是传递给next/image的width属性并不表示调整图像大小的实际宽度。
正如开头示例中所指,将width={500}传递给组件将导致图像大小调整为640px的宽度,如生成的URL所示:
/_next/image?url=/images/example.jpg&w=640&q=75
如果你希望x2 retina版本使用1000px或1280px的图像宽度,那么你必将大吃一惊:实际使用的宽度为1080px。
为什么呢?
图片
Next.js将图像大小调整为可在next.config.js中定义的deviceSizes和imageSizes数组中最接近的大小。
默认情况下是:
module.exports = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
};
这里需要注意的是,使用默认配置可能会对性能产生负面影响,从而导致Lighthouse的Page Speed Insights分数降低。
这在你尝试在页面上显示大图像时,尤其明显。
例如,如果要渲染宽度为1250px的图像,则实际加载的图像宽度将为1920px。
对于x2 retina版本,所需大小与实际加载大小之间的差异变得更大,因为大小将调整为3840px。
但是,你可以通过向deviceSizes或imageSizes数组添加更多尺寸来解决这个问题。
图片
无需next/image组件即可图像优化
了解核心体系结构后,很容易看出我们可以使用Image API,而不必使用next/image。在有些场景中,这是有优势的。
首先,你可以在画布内渲染优化的图像。无论你是从外部源还是从本地存储将图像加载到画布上,都可以将正确的URL传递给API并使其无缝工作。
此外,还可以用来优化OG图像或自己创建基于
Image API位于/_next/image路由下,仅接受三个附加参数:URL、width(w)和quality(q)。
/_next/image?url=https://example.com/test.jpg&w=640&q=75
请记住,width参数由API检查,并且只能是来自deviceSizes或imageSizes配置的数字。
对本地映像使用导入
对于next/image,有两种方法可用于加载本地图像:
import Image from 'next/image';
import profileImg from './profile.jpg';
export default function Page() {
return (
<>
{}
{}
>
);
}
在处理示例、教程甚至开源项目中的本地图像时,使用绝对路径很普遍。
可以看到,除了自动宽度/高度分配之外没有显着差异。
但是,有区别。
当你通过绝对路径从公用文件夹访问图像时,Next.js遵循目标服务器的缓存策略,默认情况下,是30天的缓存策略而不是public,max-age=31536000,immutable。
对图像资源使用30天缓存策略会显著降低Lighthouse分数。
了解sizes和100vw技术
next/image组件接受sizes属性,类似于html img sizes属性。
但是,它也执行一些独特的操作。
sizes属性与srcset协同工作,接受应激活的浏览器条件和图像宽度列表。
以下是图片使用sizes的示例:
让我们深入了解细节以便理解得更透彻。当你使用Next Image而不指定sizes属性时,srcset将包含两个URL:一个用于标准版本(x1),另一个用于Retina版本(x2)。
通过这样的设置,在Retina设备上使用时,浏览器将始终选择Retina版本。这种偏好是由于在srcset中使用了1x和2x语法而产生的。
浏览器将其解释为:加载这个URL为2x像素密度,另一个URL为1x像素密度。
因此,如果桌面上的图像版本小于移动设备或平板电脑上的图像版本,则浏览器将始终使用默认的Next Image语法加载较大的版本。
然而,不幸的是,这可能会导致性能欠佳并降低Lighthouse分数。
但是,有一种方法可以指示浏览器根据合适的宽度加载图像。不是向srcset URL提供1x、2x参数,而是指定图像的宽度。
例如,浏览器中如果有以下说明:
在这种情况下,浏览器会为页面上使用的当前尺寸选择最合适的图像。
如果移动图片的宽度为600px(Retina为1200px),则将选择1080w版本。
同时,如果桌面图像仅使用300px(Retina为600px),浏览器会选择 640w。
此方法的优点在于加载最适合当前屏幕尺寸的图像,通过减小图像大小来提高性能。
下面让我们使用100vw技巧将此策略应用于Next Image。
虽然你不能直接指示Next Image在URL附近使用width(w)参数而非像素密度(1x)选项,但可以应用从Next Image的编码方式生成的解决方法:
- 如果sizes属性包含vw数字,则只会使这些尺寸大于最小deviceSize(默认为640)乘以百分比(100vw = 1,50vw = 0.5)。例如指定100vw,最终将得到8个URL。
- 如果sizes属性包含非vw数字,则srcset将包含所有大小(即deviceSizes和imageSizes的所有可能组合),总共产生16个URL。
为了说明这一点,一起来看看100vw生成的代码:
如果sizes中包含px值(例如(max-width: 1024px) 800px, 300px),则URL列表进一步扩展,达到默认配置16。
理想情况下,我更愿意为特定图像生成4个URL,类似于其他框架,而不是使用许多不必要的选项来膨胀HTML,且这些选项中可能没有一个适合我的需求。
关键点:要用更多版本填充srcset以获得在各种分辨率下更好的性能,你可以简单地将sizes设置为100vw。
此技巧强制创建8个不同尺寸——从640px开始的URL。
但是,由于此方法很容易增大HTML大小 - 特别是如果添加了额外的imageSizes或deviceSizes的话,因此慎用此方法。
我个人认为对于需要在许多不同地方使用具有不同图像比例的大型项目,这种生成平均大小版本的方法很多时候是有益的。
这些版本可以满足大多数方案,更频繁地访问缓存,同时保持易用性。
结论
Next Image简化了图像管理并有着显著优势,它提供类似于第三方解决方案的高级裁剪和精确调整大小等附加功能。
同时有专门的组件可进行微调。
我特别喜欢它的自动化方法——生成0.25x、0.5x、1x和2x宽度的四个图像版本。