avatar
instagramthreads

Ch3 - 字型與圖片優化

優化字型

為何要優化字型

  • 主要是為了要優化 core web vital 裡的 CLS (Cumulative Layout Shift) 分數。
  • 瀏覽器初始載入時,會先使用 fallback 的預設字型,而後當指定的自定義字型被載入後,可能會因爲字型大小、字距等造成 content shift。

Next.js 如何優化字型

  • Next.js 提供了 next/font 這個模組,自動優化上述問題。
  • 原理是 Next.js 會在 build time 時就將自定義字型下載為靜態資源並做 self-hosting
  • 當使用者造訪網頁時就不會有額外的 request 需要去等待載入字型檔。
  • 參考圖中程式範例, next/font/google 裡準備好了所有 Google Font 的所有字型,開發者可以直接按需引入偏好的字型。
  • 另外可以進一步指定需要的 subsets 來減少不需要的子集合,達到優化。

字型相關知識

  • 什麼是 Font subsets?
    • Google Font 有將不同語系的字型檔切割成多個子集合 (subsets)。
    • 像是上面例子中 Inter 字型裡有英文字母的拉丁語系、斯拉夫語系、越南語系等子集。

優化圖片

為何要優化圖片?

  • Next.js 可以將靜態資源如圖片放在 /public 資料夾底下,並且能直接在元件中用 <img> 去引用:
<img src="/hero.png" alt="Screenshots of the dashboard project showing desktop version" />
  • 然而,這代表你需要手動去做一些處理:
    • 確保你的圖片能在不同尺寸下有 RWD 效果
    • 在不同裝置下指定圖片尺寸
    • 做圖片的 lazy load

Next.js 如何優化圖片

圖片優化是網頁開發中一個相當大的主題,為了節省每次需要手動優化上述的問題,你可以直接使用 next/image 自動優化你的圖片。

Next.js 中的 <Image> 元件是繼承自 HTML 的 <img> tag 實作,並擁有許多自動優化的效果:

  • 尺寸優化:自動對不同裝置提供適當的圖片尺寸,並在當瀏覽器支援 WebP 與 AVIF 時能自動套用這些較現代的格式
  • 視覺穩定性:自動避免圖片載入時的 layout shift
  • 更快的網頁載入:自動套用 lazy loading,也就是圖片進入 viewport 後才會載入。並能利用 placeholder="blur"blurDataURL="data:..." 的設定來決定是否開啟載入時的模糊效果
  • 自動調整圖片尺寸來避免在小尺寸裝置上顯示過大的圖片

練習

在範例中,我們利用 <Image> 來設定 Hero image:

<Image
  src="/hero-desktop.png"
  width={1000}
  height={760}
  className="hidden md:block"
  alt="Screenshots of the dashboard project showing desktop version"
/>

如上範例,設定了 width 與 height 是較好的實作方式,這是為了避免圖片載入時的版面位移,而這個寬高的設定必需要符合原本圖片的比例


圖片優化文件部分

Usage

【Local Images】

  • 在 Next.js 中,你能直接 import local images:
import Image from 'next/image';
import profilePic from './me.png';

export default function Page() {
  return (
    <Image
      src={profilePic}
      alt="Picture of the author"
      // width={500} automatically provided
      // height={500} automatically provided
      // blurDataURL="data:..." automatically provided
      placeholder="blur" // Optional blur-up while loading
    />
  );
}
  • 如上所示,如果你使用 import local images 的方式來設定 Image 元件,那 Next.js 就能自動幫你決定寬高及 blurDataURL
  • 但要注意,dynamic import 與 require 是不支援上述效果的,只有 import 語法能在 build time 時被分析

【Remote Images】

  • 因為 Next.js 並沒有權限讀取你的遠端圖片,例如使用 S3 去存放圖片,所以 widthheightblurDateURL 都是需要手動設定的
  • 寬高的屬性是為了去推論合適的呈現比例來避免圖片載入時的 layout shift,但並不會影響圖片呈現的真實尺寸
  • 為了更安全的優化遠端圖片,建議能在 next.config.js 中去設定 remotePatterns 支援的 URL pattern,為了避免一些可能的惡意攻擊。例如像是網站預設是用 S3 來存放由使用者上傳的圖片,另外有提供類似 richtext 來能引入外部圖片網址的話,就會需要被擋下來:
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
      },
    ],
  },
};

Image Sizing

圖片最常見的影響性能的方式之一圖片載入時造成的 layout shift,這個性能問題對使用者來說非常煩人,以至於它有自己的核心網頁指標,稱為 CLS (累積版面配置移動)。

為了避免圖片的 layout shift,你可以指定圖片寬高來讓瀏覽器提前知道要預留多少空間給載入後的圖片。

因為 next/image 被設計用來保證良好的性能結果,所以它不能以會導致 layout shift 的方式使用,必須用以下三種方式之一來設定大小:

  1. 使用 static import 的方式設定
  2. 明確地設定 widthheight
  3. 使用 fill,讓圖片延展去填滿其父元素。

那如果不知道圖片大小怎麼辦?

  • 使用 fill 來設定
    • fill 屬性讓圖片能根據父元件去設定大小。
    • 使用 CSS 替這個圖片的父元件設定固定寬高
    • 並對圖片設定 sizes 屬性來設定各種裝置的 break points
    • 也可以使用 object-fitobject-position 來定義圖片應該如何佔據這個父元件。
  • 標準化你的圖片
    • 如果你是從你能控制的來源載入圖片,可以標準化圖片到特定尺寸與比例。
  • 修改你的 API 呼叫
    • 如果你有使用縮圖系統能透過 API 參數指定特定尺寸,你可能可以修改 API 來連同 URL 一起返回對應的圖片尺寸。

如果上述建議的方法都不適用於設定你的圖片大小,那麼 next/image 元件被設計為可以在頁面上與標準的 <img> 元素一起良好運作。

Image 元件原始碼 trace memo

  • 原始碼位置
    • packages/next/src/shared/lib/image-external.tsx
    • packages/next/src/client/image-component.tsx

References

Previous Article

Ch2 - CSS Styling