关于Next Image你可能不知道的事情
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- 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&w=640&q=75 1x, /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 2x" src="/_next/image?url=%2Fimages%2Fexample.jpg&w=1080&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
中定义的deviceSizes
和imageSizes
数组中最接近的大小。默认情况下,这些是:
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 像素。
但是,可以通过向deviceSizes
或imageSizes
数组添加更多尺寸来解决此问题(文档)。
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&w=640&q=75 1x, /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 2x " />
不幸的是,这可能会导致性能不佳和 Lighthouse 得分较低。
<img srcset=" /_next/image?url=%2Fimages%2Fexample.jpg&w=640&q=75 640w, /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 1080w " />
- If your 'sizes' attribute contains
vw
numbers, it will only keep those sizes larger than the smallestdeviceSize
(640 by default) multiplied by the percentage(100vw
= 1,50vw
= 0.5). Specifying100vw
, you will end up with 8 URLs.
如果的“sizes”属性包含vw
数字,则只会保留大于最小deviceSize
(默认为 640)乘以百分比(100vw
= 1,50vw
= 0.5)的尺寸。指定100vw
,最终将得到 8 个 URL。 - If your 'sizes' property has non-
vw
numbers, your 'srcset' will contain ALL SIZES (i.e., all possible combinations ofdeviceSizes
andimageSizes
), yielding a total of 16 URLs.
如果的“sizes”属性具有非vw
编号,则的“srcset”将包含所有 SIZES(即deviceSizes
和imageSizes
的所有可能组合),总共产生 16 个 URL。
为了说明这一点,让我们检查一下100vw
生成的代码:
<img sizes="100vw" srcset=" /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=640&q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=750&q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=828&q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=1080&q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=1200&q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=1920&q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=2048&q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=3840&q=75 3840w " src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=3840&q=75" />
理想情况下,我更愿意为特定图像生成 4 个 URL,类似于其他框架,而不是用许多不必要的选项来使 HTML 膨胀,而这些选项的大小都可能无法完美满足我的需求。
这些版本可以满足大多数场景,并可能更频繁地访问缓存,同时保持易用性。