服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - js教程 - 教你如何玩转Next Image

教你如何玩转Next Image

2024-04-09 15:37前端新世界 js教程

Next Image简化了图像管理并有着显著优势,它提供类似于第三方解决方案的高级裁剪和精确调整大小等附加功能。同时有专门的组件可进行微调。

如果你用过Next.js,那么很可能邂逅过Next Image组件。此图像优化解决方案不仅支持webp和avif等现代格式,还可以针对不同屏幕尺寸生成量身定制的多个版本。

要想获得这种魔力,只需将以下代码添加到页面:

import Image from 'next/image';

export default function Page() {
  return (
    <Image
      src="https://www.51cto.com/profile.png"
      width={500}
      height={500}
    />
  );
}

不过,就像其他任何魔法一样,只有打好坚实的基础,才能熟练的运用自如。

在本文中,我们将探讨Next Image的工作原理,并澄清一些常见误解。

核心架构

next/image的底层架构主要由三个组件组成:

  • React Next Image组件
  • Image API
  • Image优化器

教你如何玩转Next Image图片

React组件

该组件的主要功能是根据提供的属性生成正确的HTML图像输出,并构造要在srcset和src属性中填充的多个URL。

下面是Next Image组件的示例输出:

<img  loading="lazy" 
    
    
  decoding="async" 
  data-nimg="1" 
    
  srcset="/_next/image?url=%2Fimages%2Fexample.jpg&w=640&q=75 1x, 
      /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 2x" 
  src="/uploads/allimg/240409/153P5F50-2.jpg&w=1080&q=75"
>

生成的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标记,以防止布局偏移。

教你如何玩转Next Image图片

正如之前所说,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 Image图片

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图片

无需next/image组件即可图像优化

了解核心体系结构后,很容易看出我们可以使用Image API,而不必使用next/image。在有些场景中,这是有优势的。

首先,你可以在画布内渲染优化的图像。无论你是从外部源还是从本地存储将图像加载到画布上,都可以将正确的URL传递给API并使其无缝工作。

此外,还可以用来优化OG图像或自己创建基于<picture>标签的组件以获得更好的艺术指导。

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 (
    <>
      {/* Using absolute path */}
      <Image src="https://www.51cto.com/profile.png" width={500} height={500} />
      {/* Using imported image via relative path */}
      <Image src={profileImg} />
    </>
  );
}

在处理示例、教程甚至开源项目中的本地图像时,使用绝对路径很普遍。

可以看到,除了自动宽度/高度分配之外没有显着差异。

但是,有区别。

当你通过绝对路径从公用文件夹访问图像时,Next.js遵循目标服务器的缓存策略,默认情况下,是30天的缓存策略而不是public,max-age=31536000,immutable。

对图像资源使用30天缓存策略会显著降低Lighthouse分数。

了解sizes和100vw技术

next/image组件接受sizes属性,类似于html img sizes属性。

但是,它也执行一些独特的操作。

sizes属性与srcset协同工作,接受应激活的浏览器条件和图像宽度列表。

以下是图片使用sizes的示例:

<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">

让我们深入了解细节以便理解得更透彻。当你使用Next Image而不指定sizes属性时,srcset将包含两个URL:一个用于标准版本(x1),另一个用于Retina版本(x2)。

通过这样的设置,在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
  "
/>

浏览器将其解释为:加载这个URL为2x像素密度,另一个URL为1x像素密度。

因此,如果桌面上的图像版本小于移动设备或平板电脑上的图像版本,则浏览器将始终使用默认的Next Image语法加载较大的版本。

然而,不幸的是,这可能会导致性能欠佳并降低Lighthouse分数。

但是,有一种方法可以指示浏览器根据合适的宽度加载图像。不是向srcset URL提供1x、2x参数,而是指定图像的宽度。

例如,浏览器中如果有以下说明:

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

在这种情况下,浏览器会为页面上使用的当前尺寸选择最合适的图像。

如果移动图片的宽度为600px(Retina为1200px),则将选择1080w版本。

同时,如果桌面图像仅使用300px(Retina为600px),浏览器会选择 640w。

此方法的优点在于加载最适合当前屏幕尺寸的图像,通过减小图像大小来提高性能。

下面让我们使用100vw技巧将此策略应用于Next Image。

虽然你不能直接指示Next Image在URL附近使用width(w)参数而非像素密度(1x)选项,但可以应用从Next Image的编码方式生成的解决方法:

  1. 如果sizes属性包含vw数字,则只会使这些尺寸大于最小deviceSize(默认为640)乘以百分比(100vw = 1,50vw = 0.5)。例如指定100vw,最终将得到8个URL。
  2. 如果sizes属性包含非vw数字,则srcset将包含所有大小(即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="/uploads/allimg/240409/153P56433-6.jpg&w=3840&q=75"
/>

如果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宽度的四个图像版本。

原文地址:https://mp.weixin.qq.com/s/MY2S9TvRr6DeERr5BJ_h0A

延伸 · 阅读

精彩推荐
  • js教程微信小程序实现视频播放器发送弹幕

    微信小程序实现视频播放器发送弹幕

    这篇文章主要为大家详细介绍了微信小程序实现视频播放器发送弹幕,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一...

    小脆筒style4312022-03-09
  • js教程js实现拖拽拼图游戏

    js实现拖拽拼图游戏

    这篇文章主要为大家详细介绍了js实现拖拽拼图游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    一个学前端的小菜鸟11692022-01-12
  • js教程五件关于JavaScript中this参数的事

    五件关于JavaScript中this参数的事

    this 关键字是 JavaScript 中最令人困惑的部分之一,本文试图通过介绍有关它的五个重要事项来阐明其目的和用法。...

    web前端开发3942022-11-16
  • js教程javascript实现数字时钟效果

    javascript实现数字时钟效果

    这篇文章主要为大家详细介绍了javascript实现数字时钟效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    一颗不甘坠落的流星11912022-01-17
  • js教程js制作提示框插件

    js制作提示框插件

    这篇文章主要介绍了js制作提示框插件的方法,帮助大家更好的理解和使用js,感兴趣的朋友可以了解下...

    lanshanxiao10342021-12-18
  • js教程JavaScript实现鼠标经过表格行给出颜色标识

    JavaScript实现鼠标经过表格行给出颜色标识

    这篇文章主要为大家详细介绍了JavaScript实现鼠标经过表格行给出颜色标识,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参...

    KathyLJQ8972022-02-27
  • js教程Javascript正则深入以及十个非常有意思的正则实战

    Javascript正则深入以及十个非常有意思的正则实战

    对于正则的基本用法笔者这里就不总结了,这里重点介绍一些比较有用且难懂的知识点.在最后笔者会写10个经典的正则案例, 供大家学习参考, 或者在工作中...

    趣谈前端6452024-03-04
  • js教程JS小知识,分享十个有用 JavaScript 小技巧

    JS小知识,分享十个有用 JavaScript 小技巧

    您可能已经知道 JavaScript 是世界上使用最广泛的编程语言。它用于 Web、移动混合应用程序、服务器端 (NodeJS) 和各种其他应用程序。由于它可用于在 Web 浏览...

    前端达人5122024-01-03