本文へ移動
aapp-hacks
← 記事一覧へ
著者
app-hacks
公開日

Astro / Image Optimization / Web Performance

Astro公式の`<Image />`コンポーネントを活用した画像最適化とWebP配信

astro:assetsのImageコンポーネントで形式、寸法、レスポンシブ表示を管理し、画像由来のCLSを防ぐ。

画像は本文の理解を助ける一方、元ファイルをそのままimgへ渡すと、必要以上に大きなデータを配信したり、読み込み後にレイアウトが動いたりする。Astroのastro:assetsが提供する<Image />コンポーネントは、ビルド時の変換と寸法管理をテンプレート内で宣言できる。静的ブログでは、画像処理を実行時サービスへ任せず、ビルド成果物として確定できる点が扱いやすい。

ローカル画像をimportする

変換対象の画像はsrc/assets配下へ置き、ES Modulesとしてimportする。public配下の画像はそのまま配信されるため、Astroがファイル内容を解析して最適化する対象にはならない。

---
import { Image } from 'astro:assets';
import cover from '../assets/article-cover.jpg';
---

<Image
  src={cover}
  alt="記事レイアウトの構造図"
  format="webp"
  quality={80}
  loading="lazy"
/>

ローカル画像を静的importすると、Astroは元画像の幅と高さを取得できる。生成される要素には寸法情報が含まれ、画像データの読み込み前からブラウザが表示領域を確保できる。装飾ではない画像には内容を説明するaltを付ける。前後の本文を繰り返すのではなく、画像が伝える情報を短く書く。

format="webp"は出力形式を明示する。元画像がJPEGでも、ビルド時にWebP版が生成される。常にWebPが最小になるとは限らず、透過、線画、既に最適化された画像など性質によって適切な形式は異なる。形式とqualityは一律の慣習ではなく、画像の用途と見た目を確認して決める。

表示サイズを制御する

元画像の解像度を持つだけでは、記事本文での表示幅が適切になるとは限らない。単一サイズへ縮小するならwidthを指定し、CSSではコンテナ幅を超えないようにする。

<Image
  src={cover}
  alt="記事カードのレスポンシブ配置"
  width={960}
  format="webp"
  class="h-auto w-full rounded-xl"
/>

ローカルimportではアスペクト比が分かるため、片方の寸法からもう片方を保った変換ができる。CSSでwidth: 100%height: autoを組み合わせれば、狭い画面ではコンテナへ合わせて縮む。HTMLのwidthとheight属性はCSS上の固定表示サイズではなく、比率を予約する材料として働く。

複数の画面幅に合わせた候補を生成する場合は、widthssizesを組み合わせる。sizesは実際のレイアウトで画像が占める幅をブラウザへ伝える。

<Image
  src={cover}
  alt="デスクトップとモバイルの記事画面"
  widths={[480, 768, 960]}
  sizes="(max-width: 48rem) calc(100vw - 2rem), 48rem"
  format="webp"
  class="h-auto w-full rounded-xl"
/>

候補幅を大量に増やすと、ビルド時間と生成物が増える。実際の本文最大幅と代表的なビューポートに合わせ、必要な候補だけを用意する。本文が最大48remなら、それを大幅に超える表示用画像を作っても通常の閲覧では利用されにくい。

CLSを防ぐ寸法設計

CLSは、読み込み中に既存コンテンツが予期せず移動する現象を評価する指標である。画像の寸法が分からないままHTMLを表示すると、最初は高さゼロとして本文が詰まり、画像取得後に下の文章が押し下げられる。

Astroが寸法を取得できるローカルimportでは、<Image />がwidthとheightを出力するため、この予約領域を作りやすい。外部URLをsrcへ渡す場合は、幅と高さを自分で指定するか、利用しているAPIが対応する寸法推論機能を明示的に使う。外部画像の内容はビルド後に差し替わる可能性があるため、安定したCDNと固定アスペクト比を前提にする。

---
import { Image } from 'astro:assets';
---

<Image
  src="https://images.example.com/diagram.png"
  alt="API処理の流れ"
  width={1200}
  height={675}
  format="webp"
/>

CSSで固定heightだけを与え、画像ごとの比率が異なる場合はobject-fit: coverで切り抜かれる。カードのサムネイルでは妥当でも、図表では端の情報を失う。記事内の技術図は原則として元の比率を保ち、レイアウト都合の切り抜きを避ける。

読み込み優先度を使い分ける

最初の表示領域にある主要画像までloading="lazy"にすると、表示開始が遅れる場合がある。ファーストビューの重要画像は通常読み込みとし、記事本文の途中や一覧下部にある画像へlazy loadingを使う。すべての画像を高優先度にするのも競合を増やすため、主要な一枚だけを候補にする。

Lighthouseの指摘へ対応するときは、スコアだけでなく原因を見る。適切な寸法候補が選ばれているか、表示サイズより過大なファイルを配っていないか、widthとheightがHTMLへ出ているか、ファーストビュー画像を遅延していないかを確認する。画像以外のJavaScriptやフォントが主因なら、形式をWebPへ変えるだけでは解決しない。

画像最適化の実装は、形式変換だけで完了しない。最適化対象をsrc配下へ置き、<Image />で用途に合う出力幅を指定し、寸法情報で領域を予約し、表示位置に応じて読み込み方を選ぶ。この一連をコンポーネントへ明示することで、記事追加時にも同じ規則を再利用できる。