logo

关于Next Image你可能不知道的事情

作者
Modified on
Reading time
17 分钟阅读:..评论:..

如果使用过 Next.js,可能遇到过 Next Image 组件。这种无忧的图像优化解决方案不仅提供对 webp 和 avif 等现代格式的支持,而且还生成针对不同屏幕尺寸定制的多个版本。

要利用这种魔力,只需将以下代码添加到的页面即可:

import Image from 'next/image'; export default function Page() { return ( <Image src="/profile.png" width={500} height={500} alt="Picture of the author" /> ); }

然而,与任何魔法一样,都需要有坚实的努力基础才能使其顺利发挥作用。在本文中,我们将探讨 Next Image 的工作原理,并澄清一些围绕它的常见误解。

核心架构

<font style="color:rgb(0, 0, 0);">next/image</font>的底层架构主要由三个组件组成:

  • React Next Image Component
  • Image API
  • Image Optimizer

React

该组件的主要功能是根据提供的属性生成正确的 HTML 图像输出,并构造多个要填充到<font style="color:rgb(0, 0, 0);">srcset</font><font style="color:rgb(0, 0, 0);">src</font>属性中的 URL。以下是下一个图像组件的输出示例:

<img alt="Example" loading="lazy" width="500" height="500" decoding="async" data-nimg="1" style="color:transparent" srcset="/_next/image?url=%2Fimages%2Fexample.jpg&amp;w=640&amp;q=75 1x, /_next/image?url=%2Fimages%2Fexample.jpg&amp;w=1080&amp;q=75 2x" src="/_next/image?url=%2Fimages%2Fexample.jpg&amp;w=1080&amp;q=75" >

让我们仔细看看生成的 URL:

/_next/image?url=/images/example.jpg&w=640&q=75

此编码 URL 接受两个参数: <font style="color:rgb(0, 0, 0);">w</font> (宽度)和<font style="color:rgb(0, 0, 0);">q</font> (质量),这两个参数在解码版本中更加明显。

可以发现没有<font style="color:rgb(0, 0, 0);">h</font> (高度)属性,但我们将在本文后面讨论这一点。

Next Image API

Next Image API 用作图像代理,类似于IPX 。它执行以下任务:

  • 接受图像 URL宽度质量
  • 验证参数
  • 确定缓存控制策略
  • 处理图像
  • 以用户浏览器支持的格式提供图像

Image Optimizer 图像优化器

这可能会导致生产环境和本地环境之间出现视觉上不同的行为,特别是在尝试将图像的背景颜色与页面背景相匹配时。

Outcomes 结果

了解了next/image背后的主要架构后,我们可以揭穿常见的误解,并收集有关如何更有效地利用它的更多见解。

next/image does not crop 下一个/图像不裁剪

开发人员中的一个常见误解是next/image可以裁剪他们的图像。出现这种混乱的原因是可以将宽度、高度和填充属性传递给组件,从而造成图像已被裁剪的印象。事实上,情况并非如此。

下一个图像组件主要需要分配给 img 标签的宽度和高度,以防止布局移位。

img, video { max-width: 100%; height: auto; }

Displayed image width ≠ loaded image width

显示图像宽度≠加载图像宽度 另一个潜在的混淆点是传递给next/image width 属性并不代表图像将调整大小的实际宽度。正如我们在文章开头的示例中指出的,将width={500}传递给组件将导致图像大小调整为 640px 的宽度,如生成的 URL 所示:

/_next/image?url=/images/example.jpg&w=640&q=75

Next.js 将图像大小调整为可以在next.config.js中定义的deviceSizesimageSizes数组中最接近的大小。默认情况下,这些是:

module.exports = { images: { deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], }, };

这里需要注意的重要一点是,使用默认配置会对性能产生负面影响,导致 Lighthouse 的页面速度洞察分数降低。当尝试在页面上显示大图像时,这一点变得尤其明显。

例如,如果要渲染宽度为 1250px 的图像,则实际加载的图像宽度将为 1920px。对于 x2 视网膜版本,所需尺寸和实际加载尺寸之间的差异甚至更大,因为这些版本的尺寸将调整为 3840 像素。

但是,可以通过向deviceSizesimageSizes数组添加更多尺寸来解决此问题(文档)。

Image optimization can be used without the next/image component

图像优化可以在没有next/image组件的情况下使用
了解核心架构后,很容易看出可以使用 Image API 而不必使用next/image 。在多种情况下,这可能是有益的。

/_next/image?url=https://example.com/test.jpg&w=640&q=75

Use import for local images

使用导入本地图像 使用next/image ,可以使用两种方法来加载本地图像:

import Image from 'next/image'; import profileImg from './profile.jpg'; export default function Page() { return ( <> {/* Using absolute path */} <Image src="/profile.png" width={500} height={500} alt="Picture of the author" /> {/* Using imported image via relative path */} <Image src={profileImg} alt="Picture of the author" /> </> ); }

Understanding Sizes and the 100vw Technique

了解尺寸和 100vw 技术
next/image组件接受一个称为“sizes”的属性,类似于 html img 尺寸属性。然而,与我们讨论的其他方面一致,它也执行一些独特的操作。

“sizes”属性与“srcset”协同工作,并接受应激活它们的浏览器条件和图像宽度列表。如果对此不熟悉,我建议查看这些文档和这个codesandbox 示例。这是使用“尺寸”的图像示例:

<img srcset="/img/html/vangogh-sm.jpg 120w, /img/html/vangogh.jpg 193w, /img/html/vangogh-lg.jpg 278w" sizes="(max-width: 710px) 120px, (max-width: 991px) 193px, 278px">

通过此设置,在 Retina 设备上使用时,浏览器将始终选择 Retina 版本。这种偏好的产生是由于在“srcset”中使用了 1x 和 2x 语法。

<img srcset=" /_next/image?url=%2Fimages%2Fexample.jpg&amp;w=640&amp;q=75 1x, /_next/image?url=%2Fimages%2Fexample.jpg&amp;w=1080&amp;q=75 2x " />

不幸的是,这可能会导致性能不佳和 Lighthouse 得分较低。

<img srcset=" /_next/image?url=%2Fimages%2Fexample.jpg&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fimages%2Fexample.jpg&amp;w=1080&amp;q=75 1080w " />
  1. If your 'sizes' attribute contains vw numbers, it will only keep those sizes larger than the smallest deviceSize (640 by default) multiplied by the percentage(100vw = 1, 50vw = 0.5). Specifying 100vw, you will end up with 8 URLs.
    如果的“sizes”属性包含vw数字,则只会保留大于最小deviceSize (默认为 640)乘以百分比( 100vw = 1, 50vw = 0.5)的尺寸。指定100vw ,最终将得到 8 个 URL。
  2. If your 'sizes' property has non-vw numbers, your 'srcset' will contain ALL SIZES (i.e., all possible combinations of deviceSizes and imageSizes), yielding a total of 16 URLs.
    如果的“sizes”属性具有非vw编号,则的“srcset”将包含所有 SIZES(即deviceSizesimageSizes的所有可能组合),总共产生 16 个 URL。

为了说明这一点,让我们检查一下100vw生成的代码:

<img sizes="100vw" srcset=" /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=3840&amp;q=75 3840w " src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&amp;w=3840&amp;q=75" />

理想情况下,我更愿意为特定图像生成 4 个 URL,类似于其他框架,而不是用许多不必要的选项来使 HTML 膨胀,而这些选项的大小都可能无法完美满足我的需求。

这些版本可以满足大多数场景,并可能更频繁地访问缓存,同时保持易用性。

Conclusions 结论

翻译自原文:https://pixelpoint.io/blog/next-image/