ホーム > Gatsby > 【Gatsby.js】記事内の画像を圧縮できるgatsby-remark-images の使い方
Gatsby

【Gatsby.js】記事内の画像を圧縮できるgatsby-remark-images の使い方

いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。

Gatsby.js のプラグインである、gatsby-remark-images の使い方についてまとめました。

gatsby-remark-images とは?

まず、Gatsby.js のプラグインの中で、remark と名のつくのプラグインは、マークダウン記事を整形してビルドしてくれるツールのことが多いです。

この gatsby-remark-images は、マークダウン記事内で書かれた画像ファイルを、例えば軽量化したり、大きさを整えたりして出力してくれるというのがメインの機能になっています。

機能

ドキュメント

実際に使ってみた仕様感

  1. 画像をビルドしレスポンシブ化してくれる
  2. ページ読み込み時、画像の読み込みによるズレ防止(CLS: Cumulative Layout Shift)
  3. デバイスに応じて最適な画像サイズ
  4. 画像を完全に読み込む前、ほぼ 0 バイトのぼかし画像を表示してくれる
  5. WebP による画像の軽量化
  6. 遅延読み込み

といった点が嬉しい点でした。

導入方法

必要なプラグインをコマンドで入れます

npm install gatsby-remark-images gatsby-plugin-sharp gatsby-transformer-remark

gatsby.config.js に追記します

プラグインの重複に気をつけて、gatsby-remark-images を入れます。

plugins: [
  `gatsby-plugin-sharp`,
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        {
          resolve: `gatsby-remark-images`,
          options: {
            maxWidth: 620,
          },
        },
      ],
    },
  },
]

画像を filesystems が定義している場所に置く、または新しく定義する

gatsby.config.js

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content-images`,
        path: `${__dirname}/src/images`,
      },
    },

画像を相対パスで md ファイルから呼び出す

パスは人の環境によると思うので変わってくると思います。

![](../../images/sample.png)

パスの指定などが分からなかったらこちらの記事のときに詳しく書いています。

Gatsby.js の記事内の画像を webp にして軽量化する方法は簡単だった

詳細に導入した挙動を見る

出力された結果

<a
  class="gatsby-resp-image-link"
  href="/static/70b8b9146729bb8ea24a7cbd117c0fd7/21b4d/mailtrap.png"
  target="_blank"
  rel="noopener"
  style="display: block;"
>
  <span
    class="gatsby-resp-image-background-image"
    style='padding-bottom: 56.3291%; position: relative; bottom: 0px; left: 0px; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB8klEQVR42n1Sz2sTQRjda7E3wZvWopYePFgL1bb2IhZBIfXYv6UH0ZNS9WRQ/xRPohdRkSIiaNBKQ2o3SZPsr9md2czsPt9MUmNscOAx385+35v3fW+882sbOHXxOrYeVGFXHAtobWCMQTeIEfK7KEqicDBmhEnLW1ytYPbCCu5vP3MHqVTQw+Taz33sNXyINEWcWAiITEIqhT4vnUi4vr6J+SsVVB8+BVSGpNFAfnAANH0kQiCMEkdk9yhOoFSOvN93xWVZHoO3unYHly/dQPXJc5dkkgQQBHfFwoi7yHhRKpBZZRyF0hqS/ybBm1/ZwMm5a7g7bNnO7miJNEMvjJCTIKC6mLFWklAONvdfeHPLFZyYXca97aFCFlO7i2WeUyFN4VnYbCL3fSCKUHa7Dkd5YzM8t3Qb02evkvC4QkVCq7JgK2GrhZSG6GKyu38ITy/cxNTM0kjhX4SSBghpHdVIWm0k7TZkHMPIDMbuLpYwVG2icNDymf8QWlMOf/kIG/vI6nVIui97PWSdjovNYZsmkpTqDUcyTvjoxYCQKmBnRGdNECBlYaf2jcbHSHXfXWJNylmsywJ8LOMtzyzewpSd4eMBod7dRVnfQxmyBZJ1ewFqtR94/fIV3rzbwfuPn/H2wyd8+fodJefp3l8xeoe/AeOtFm22gmcCAAAAAElFTkSuQmCC"); background-size: cover; display: block; opacity: 0;'
  ></span>
  <picture>
    <source
      srcset="/static/70b8b9146729bb8ea24a7cbd117c0fd7/81b7c/mailtrap.webp 158w /static/70b8b9146729bb8ea24a7cbd117c0fd7/6ea66/mailtrap.webp 315w /static/70b8b9146729bb8ea24a7cbd117c0fd7/8aab1/mailtrap.webp 630w /static/70b8b9146729bb8ea24a7cbd117c0fd7/a70f5/mailtrap.webp 945w /static/70b8b9146729bb8ea24a7cbd117c0fd7/4ef06/mailtrap.webp 1260w /static/70b8b9146729bb8ea24a7cbd117c0fd7/af3f0/mailtrap.webp 1280w"
      sizes="(max-width: 630px) 100vw, 630px"
      type="image/webp"
    />
    <source
      srcset="/static/70b8b9146729bb8ea24a7cbd117c0fd7/c26ae/mailtrap.png 158w /static/70b8b9146729bb8ea24a7cbd117c0fd7/6bdcf/mailtrap.png 315w /static/70b8b9146729bb8ea24a7cbd117c0fd7/f058b/mailtrap.png 630w /static/70b8b9146729bb8ea24a7cbd117c0fd7/40601/mailtrap.png 945w /static/70b8b9146729bb8ea24a7cbd117c0fd7/78612/mailtrap.png 1260w /static/70b8b9146729bb8ea24a7cbd117c0fd7/21b4d/mailtrap.png 1280w"
      sizes="(max-width: 630px) 100vw, 630px"
      type="image/png"
    />
    <img
      class="gatsby-resp-image-image"
      src="/static/70b8b9146729bb8ea24a7cbd117c0fd7/f058b/mailtrap.png"
      alt="mailtrap"
      title=""
      loading="lazy"
      decoding="async"
      style="width: 100%; height: 100%; margin: 0px; vertical-align: middle; position: absolute; top: 0px; left: 0px; opacity: 1; color: inherit; box-shadow: white 0px 0px 0px 400px inset;"
    />
  </picture>
</a>

デバイスに応じて最適な画像サイズ

出力された結果を見ると、

158w, 315w, 630w, 945w, 1260w, 1280w に対応するファイルが定義されています。

これは、デバイスの横幅に応じて無駄に大きなファイルを取得させないようにしてくれています。

ちなみに、630 が max-width で指定しているもの、

1280 がオリジナル画像の横幅だと思われます。

ページ読み込み時、画像の読み込みによるズレ防止(CLS: Cumulative Layout Shift)

picture タグの上にある span タグで画像のアスペクト比に応じた padding-bottom が与えられており、これが正規の画像を読み込むまでの間、空間を埋めてくれており、画像が読み込まれてもズレない仕組みなっているようです。

ちなみに、

画像の幅 = 630px
画像の高さ = 355px

アスペクト比
    = (高さ / 幅) * 100
    = (355 / 630) * 100
    = 56.3291%

です。画像によって%が違うので、画像の大きさを取得して計算して HTML に反映してくれています。すごすぎ。

画像を完全に読み込む前、ほぼ 0 バイトのぼかし画像を表示してくれる

同様にさきほどの span タグを見ると background-image がありますが、これが base64 で圧縮されたぼかし画像のようです。

これが画像が表示されるまでの間、背景として表示されるという仕組みみたいです。

WebP による画像の軽量化

gatsby-config.jsにてオプションで設定することにより webp に圧縮し画像を軽量化してくれます。

オプションの設定については後述するためここでは割愛します。

遅延読み込み

img タグに

loading="lazy"

があり、遅延読み込みをしてくれています。

また、

decoding="async"

があり、非同期に画像データを取りに行ってくれ、ページ内の他の情報の取得の邪魔にならないようにしてくれています。

これがデフォルト設定で後述のオプションで変更が可能です。

オプションの設定

options のオブジェクトに追記することで設定を変更することができます。

plugins: [
  `gatsby-plugin-sharp`,
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        {
          resolve: `gatsby-remark-images`,
          options: {
            maxWidth: 620,
          },
        },
      ],
    },
  },
]

ドキュメント

ドキュメントを読めば大体分かりますが、要約して以下に説明します。

最大横幅の指定

画像の最大横幅を指定でき、余白が余ったら中央寄せになります。

options: {
  maxWidth: 620
}

画像のリンクを作成するかどうか

記事内の画像をクリックすると、別窓で画像を開きオリジナル画像(圧縮前)を表示することができる機能を、True False で切り替えます。デフォルトで表示されます。

拡大できないと不便な画像などで使えそうです。

options: {
  linkImagesToOriginal: false
}

ALT の文字を画像の下につけるかどうか

gatsby remark image1

↑ の画像のように、画像の下にテキストをつけられます。テキストは ALT タグに書かれているテキストのようです。

options: {
  showCaptions: true
}

画像の下につけるテキストをマークダウンで読む

gatsby remark image2

↑ の画像のようにマークダウンでテキストを表示してくれるようです。

showCaptions が False だとこれは表示されません。

options: {
  showCaptions: true,
  markdownCaptions: true,
},
![## あああ](../../images/sample.png)

画像囲うタグに対してスタイルを付与

picture タグを wrap している span タグに、style を追加できます。

色々できそうですが、background はホバー時の色が変わりました。

options: {
    wrapperStyle: "margin-bottom:10px; background: red;",
}

背景色の変更

これは、img タグに背景色が付くもののようです。

ようするに、画像が何らかの原因で 404 などのエラーで読み込めなかったとき、何色にするか、という設定のようです。

ほとんどの場合、記事の背景と同じ色にすれば変な表示にはならなそうです。

  • transparent に設定すると、画像の背景が透明
  • none に設定すると、画像の背景が完全に除去
options: {
   backgroundColor: "transparent",
},

圧縮時の解像度

よっぽど重い時に解像度を下げる時に使うと思います。

これをする前に、Avif や webp での圧縮を試した方が良いと思います。

options: {
    quality: 50
},

webp で出力するかどうか

オリジナル画像を webp に圧縮し、良きなにしてくれます。

webp は、jpg より更に圧縮効率で軽量化できます。

透明にも対応してくれるので丸い画像とかでも良い感じになります。

これ自前でやるの相当大変だと思うので、本当にありがたいです。

options: {
  withWebp: true
  //withWebp: { quality: 80 },
},

Avif で出力するかどうか

オリジナル画像を Avif に圧縮し、良きなにしてくれます。

webp より更に上の圧縮効率で軽量化できます。

これ自前でやるの相当大変だと思うので、本当に本当にありがたいのだ。

思わず、ずんだもんになってしまうくらいすごいことなのだ。

options: {
    withAvif: true,
    // withAvif: { quality: 80 },
},

読み込み中のぼやけた画像を変えたい

tracedSVG というオプションから、変更が可能なようです。

正直やり方が分からなかったのだ。これには僕も愛想笑いするしかないのだ。

ぼやけた画像のままがおしゃれなのだ。僕はこれでいくと決めているのだ。

【翻訳】blur up" エフェクトの代わりに、プレースホルダ画像にトレースされた SVG を使用する。トレースされた SVG をデフォルト設定(ここにある)で使用する場合は true を、デフォルトを上書きする場合はオプションのオブジェクトを渡す。例えば、 { color: 「#F00」, turnPolicy: 「turnpolicy_majority」 を渡すと、トレースの色を赤に、ターンポリシーを TURNPOLICY_MAJORITY に変更します。利用可能なオプションの完全なリストと説明については、node-potrace パラメータ・ドキュメントを参照してください。

https://www.gatsbyjs.com/plugins/gatsby-remark-images/#options

(自分の検証環境だと以下で何が変わるのか分かりませんでした)

tracedSVG: { color: "#F00", turnPolicy: "TURNPOLICY_MAJORITY" }

loading 属性を変更したい

img タグに付された、loading="lazy"を変更することができます

遅延読み込みの設定です。

options: {
    loading: 'lazy'// eager,auto
},

非同期に読み込むかどうか

img タグに付された、decoding="async"を変更することができます

画像の読み込みを非同期にし、他要素の読み込みに影響させない設定です。

options: {
    decoding: 'async'// sync or auto
},

透明ピクセルを含んだ画像は、ぼかしアップを無効に

透明ピクセルを含んだ画像は、不自然な表示になるという課題があり、透明ピクセルを含む画像のときはぼかしアップを無効にすることができる設定なようです。

【翻訳】 エッジに透明ピクセルを含む画像は、エッジがぼやけた画像になります。その結果、これらの画像はこのプラグインで使用されている「ぼかしアップ」テクニックとは相性が悪くなります。

options: {
    disableBgImageOnAlpha: true,
}

背景画像やスタイルの削除

【翻訳】背景画像とそのインライン・スタイルを削除します。
AMP の Stylesheet too long エラーを防ぐのに便利です。

AMP とは、Web コンテンツを高速表示させるための手法を指します。

特段理由がなければ、設定する必要はなさそうです。

options: {
    disableBgImage: true
},

画像のレスポンシブのブレイクポイントを変更

先ほどの出力結果では、

158w, 315w, 630w, 945w, 1260w, 1280w

のブレイクポイントが指定されていることがわかりました。

options: {
    srcSetBreakpoints: [200, 340, 520, 890],
},

今回このようにしてみました。

結果、

<source
  srcset="/static/70b8b9146729bb8ea24a7cbd117c0fd7/772e8/mailtrap.png 200w /static/70b8b9146729bb8ea24a7cbd117c0fd7/9f933/mailtrap.png 340w /static/70b8b9146729bb8ea24a7cbd117c0fd7/69902/mailtrap.png 520w /static/70b8b9146729bb8ea24a7cbd117c0fd7/f058b/mailtrap.png 630w /static/70b8b9146729bb8ea24a7cbd117c0fd7/4ef49/mailtrap.png 890w /static/70b8b9146729bb8ea24a7cbd117c0fd7/21b4d/mailtrap.png 1280w"
  sizes="(max-width: 630px) 100vw, 630px"
  type="image/png"
/>

200w, 340w, 520w, 630w, 890w, 1280wのブレイクポイントが指定されています。

630 と 1280 が前回と同じで、他は今回設定した数字になりました。

630 は他画像も共通で max_width で指定した数字、

他の画像ではこの 1280 の数字だけ変わるのでオリジナル画像の横幅と推測できます。

オプションで良かったもの

withWebpwithAvifが本当にお気に入りです。

例えば 180kb の画像が圧縮後、300b とかになります。

約 1/600 でページ上での見た目はそんなに変わらないし、画像をクリックすると元画像が表示されるので UX 的に悪くないと思います。

感謝。

デメリット

ビルド時間が増えてしまうことくらいだと思います。

とはいえ、自分は Netlify の無料枠で収まっていますが、記事 200 記事ほど、画像 150 枚ほどで、ビルド時間は全部で 5 分ほどでした。

特に増えた感じもしないのが正直な感想で、これくらいの画像の量であれば影響は少なさそうです。

また、一度ビルドした画像は多分保持してくれる(はず)なので、そんなにこのプラグインを入れてコストが増すようなことは少ないんじゃないかと予想しています。

まとめ

gatsby-remark-imagesというプラグインを使った挙動と感想についてまとめてみました。

誰かの参考になれば幸いです。

フィードバックのお願い
この記事のフィードバックがありましたらYoutubeの適当な動画にコメントしていただいたり、お問い合わせからご連絡ください。