Day28 - Next.js 如何优化图片在网页上的体验?

Image optimzation

在 Next.js 10 版以後发布了 <Image /> 这个 component,是由 Google Chrome Team 帮他们建造的,主要用来解决图片载入效能的问题。

Basic Usage

<Image /> component 使用起来非常地方便,只要先从 next/image 後即可开箱使用:

import Image from "next/image";

function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src="/me.png"
        alt="Picture of the author"
        width={500}
        height={500}
      />
      <p>Welcome to my homepage!</p>
    </>
  );
}

export default Home;

<Image /> 元件解决的问题

<Image /> 解决的效能问题可以分成 5 个面向来讨论:

  • 不合适的图片大小
  • 图片格式
  • 图片预载入
  • 延迟载入
  • 是否设置图片的 widthheight

不合适的图片大小

有一项问题是图片是 2000x2000 的图片时怎麽办?在手机版的网页中,我们不希望让使用者载入过大的图片档案。要根据使用者的装置大小载入合适的图片,可以使用 srcset 这个 <img /> 的属性:

<img srcset="elva-fairy-480w.jpg 480w,
             elva-fairy-800w.jpg 800w"
     sizes="(max-width: 600px) 480px,
            800px"
     src="elva-fairy-800w.jpg"
     alt="Elva dressed as a fairy">

而如果要在网站中使用 srcset 这个属性,最大的问题是要如何有效地生成不同大小的图片,而且对於工程师来说不会造成负担。以往要做到这件事需要很多的设定,例如使用 webpack、gulp 等工具对图片进行处理。

而在 Next.js 中的 <Image /> 元件已经帮我们做掉这件事,几乎不用设定就可以让网页可以根据使用者的装置大小载入合适的图片。

图片格式

现今有许多较新的图片档案格式比较久远的图片格式拥有更小的档案大小,例如 WebP、AVIF,而 WebP 比 JEPG 的档案格式甚至少了 30%。如果想要根据使用者的浏览器判断要用哪种格式的图片,在原生的 HTML 中也是可以使用 srcset 这个 <img /> 的属性解决。

最麻烦的地方同样在於要设定自动化转换图片的程序,实际上 <Image /> 也包含自动转换图片格式的功能,我们不必再做其他设定,预设就会根据使用者的浏览器给予 WebP 或原生的图片格式。

图片延迟载入 (lazy loading)

对於使用者来说浏览一个画面载入越少资源越好,因为关系到使用者能够更快速看到页面中显示第一个像素 (First Contentful Paint),此外越少资源代表 Large Contentful Paint 的评分也就好。换句话说,使用者在浏览页面时实际上只需优先载入看到的部分 (viewport),看不到的部分可能等待使用者滚动画面,接近该区块时才载入图片,藉此让使用者不必在一开始就载入所有的资源。

图片预载入 (preload)

Next.js 将 CSS 与 JavaScript 视为比图片有更高优先权,但是有些情况例外,像是在 landing page,在最上面的 viewport 有一些图片,按照 <Image /> 预设的设定会是 lazy loading,因此使用者在载入页面後需要等待一段时间才会看到图片。

我们会希望 Large Contentful Paint 可以有更好的分数,所以想要提高图片的载入优先度,一般的做法会使用 <link rel="preload"> ,可是如果有很多张图片都需要加入这个设定到 <head> 不免让程序码不好看, <Image /> 可以让工程师更简地设置属性,设定 priority={true} 让 Next.js 帮我们自动生成 preload 的 <link>

<Image
  src="/me.png"
  alt="Picture of the author"
  width={500}
  height={500}
  priority={true}
/>

是否设置图片的 widthheight

heigthwidth 是很重要的属性,有设定图片的长跟宽才能让浏览器避免在载入时不会 reflow,因此降低 Cumulative layout shift (CLS) 的分数。

<Image> component 也需要设置 heightwidth ,但是这两个属性并不会直接影响图片显示的长跟宽,而是用来决定图片的比例

Automatic Image Optimization

也许你会想到一个问题时,像是电商网站有数以万计的图片,难道要在打包时处理大量的图片转换吗?这个跟 Incremental Static Regeneration 很相似,都是在使用者浏览网页时才会动态地处理,不会在打包时一口气处理大量的档案,这是非常费时的一件事情。

Reference


<<:  【设计+切版30天实作】|Day29 - Footer区块 - 切出最後一步,看似不起眼但必须存在的footer

>>:  [Day28] 打造高效团队,先累积社会资本

DAY 6 - 狗狗

大家好~ 今天的画画时间又来了 但是 我家狗狗今天送医住院了 可能活不了很多天了........ 所...

【JavaScript】检查Array阵列的各种方式

本篇搭配 LeetCode 1.Two Sum 题目: Given an array of inte...

NoSQL的格式(一)

再来检核DynamoDB的资料, 比较与SQL的不同 回到DynamoDB Portal, 点选第一...

Webpack 笔记三(webpack loader dev server)

dev server 利用 source-map 可以更好的 debug 如果我在程序码里面加入一个...

[D01] 数位影像的基本介绍(1)

在生活中处处都在存在着影像 ,将随手可得的照片资料以数位的方式保存,称作数位影像! 一般的相片透过机...