---
title: "Astroの画像最適化とpreload・prefetch｜astro:assetsの実装【Astro 7.4】"
url: "https://www.issoh.co.jp/tech/details/2762/"
published: 2024-06-25
updated: 2026-11-01
categories: ["Astro"]
publisher: "株式会社一創"
---

# Astroの画像最適化とpreload・prefetch｜astro:assetsの実装【Astro 7.4】

Astroでファーストビューの画像やフォントを先に読ませる公式の手段は3つあります。取得優先度を上げる`<Image>`の`priority`、`getImage()`の結果で`<link rel="preload">`を書く方法、Fonts APIの`<Font preload>`です。ただし`getImage()`で作ったpreloadは、レスポンシブ画像（`layout`指定）の`<Image>`と既定値が違うため、そのままでは別のファイルを指して画像を2回ダウンロードさせます。

この記事では、Astro 7.4.4とsharp 0.35.5で実際にビルドしたHTMLとファイルサイズをもとに、astro:assetsの画像最適化、preload、ページ遷移のprefetch、画像サービスとビルド時間の管理を順に説明します。

## まとめ：Astro 7.4で画像・preload・prefetchを設定する要点

- 画像は`src/`に置いてimportし、`<Image>`か`<Picture>`に渡します。`public/`の画像は最適化されません。
- `<Picture>`のフォールバック画像は既定でPNGです。元画像がPNGなら`fallbackFormat="webp"`を指定します（800w相当で558,771バイトが5,742バイトになりました）。
- `srcset`を自動で出すには`layout`を指定します。既定は`none`で、このままだと`widths`と`sizes`、または`densities`を自分で書かない限り画像は1枚だけです。
- ファーストビューの画像は、まず`priority`を付けます。`fetchpriority="high"`などがまとめて付き、HTMLの`<img>`はブラウザがすぐ見つけるので、多くの場合preloadは要りません。
- CSS背景やJSで差し込む画像のようにHTMLに出ない画像は、`getImage()`で生成してpreloadします。`layout`付きの`<Image>`と同じファイルを指させるには、`fit: "cover"`と`position: "center"`も渡します。
- `<Picture>`はpreloadせず`priority`に任せます。
- フォントはFonts APIの`<Font preload>`でpreloadします。既定は`false`です。配列で太さを絞れます。
- ページ遷移の先読みは`prefetch: true`で有効にします。既定の`hover`はマウスが乗ってから80ミリ秒後に取得を始めます。

## astro:assetsのImage・Pictureによる画像最適化

astro:assetsは、ビルド時（静的サイト）またはリクエスト時（オンデマンド描画）に画像を変換するAstro標準の仕組みです。最適化の対象は、`src/`からimportした画像と、許可したドメインのリモート画像です。[Astro公式の画像ガイド](https://docs.astro.build/ja/guides/images/)には「Images stored in the public/ folder are never optimized.」と書かれており、`public/`に置いた画像や素の`<img>`タグはそのままコピーされるだけです。

### Imageの既定出力とqualityの調整

`<Image>`に幅だけ渡してビルドすると、次のHTMLが出ました。形式は既定でWebPに変わり、`loading="lazy"`・`decoding="async"`・`width`・`height`が自動で付きます。幅と高さが入るので、読み込み中にレイアウトがずれません。

```
---
import { Image } from "astro:assets";
import photo from "../assets/photo.png";
---
<Image src={photo} alt="山の写真" width={800} />
<Image src={photo} alt="山の写真" width={800} quality={40} />
<Image src={photo} alt="山の写真" width={800} format="avif" />

<!-- 1行目の出力 -->
<img src="/_astro/photo.4_AuFKfq_ZCIKgX.webp" alt="山の写真" loading="lazy" decoding="async" width="800" height="450">
```

元画像（1600×900のPNG、1,704,725バイト）を幅800で出したときのサイズは次のとおりです。合成した滑らかな画像なので圧縮が効きやすい点に注意してください。写真での容量差は、被写体や元画像の圧縮状態、出力品質によって変わります。

| 指定                   | 出力形式 | サイズ（バイト） |
| -------------------- | ---- | -------- |
| 既定                   | WebP | 5,742    |
| quality={40}         | WebP | 3,578    |
| format=”avif”        | AVIF | 3,837    |
| fallbackFormat=”jpg” | JPEG | 13,069   |
| Pictureのフォールバック（既定）  | PNG  | 558,771  |

`quality={40}`で約38%小さくなりました。ただし品質の劣化は画像ごとに違うので、商品写真など細部が大事な画像は目で確認してから下げてください。

### Pictureの既定フォールバック形式と変更指定

`<Picture>`は`<source>`に新しい形式を並べ、古いブラウザ向けに`<img>`のフォールバックを出します。7.4.4の`Picture.astro`は`defaultFormats = ['webp']`、`defaultFallbackFormat = 'png'`です。元画像がGIF・SVG・JPEGのときだけフォールバックは元の形式を引き継ぎます。PNGのフォールバックはPNGのままです。

```
<!-- 既定：フォールバックが558,771バイトのPNGになる -->
<Picture src={photo} alt="山の写真" width={800} />

<!-- AVIFとWebPを出し、フォールバックもWebPにする -->
<Picture src={photo} alt="山の写真" width={800} formats={["avif", "webp"]} fallbackFormat="webp" />
```

WebPは主要ブラウザがすべて対応しているので、フォールバックもWebPで困る場面はほぼありません。フォールバックのPNGは対応ブラウザでは読み込まれません。それでも`dist`の容量とビルド時間は増えるので、指定しておく方が無駄がありません。

### layout指定によるsrcset・sizesの自動生成

画面幅に応じて画像を切り替える`srcset`と`sizes`は、`layout`を`constrained`・`full-width`・`fixed`のいずれかにすると自動生成されます。`widths`と`sizes`を明示する方法もあります。`layout`の既定は`none`なので、何も指定しないと幅800の画像1枚だけです。`layout`は5.10.0で正式機能になりました。

```
// astro.config.mjs：サイト全体の既定を constrained にする
import { defineConfig } from "astro/config";

export default defineConfig({
  image: {
    layout: "constrained",
    responsiveStyles: true,
  },
});
```

`layout="constrained"`で幅800を指定すると、640w〜1600wの7本の`srcset`と`sizes="(min-width: 800px) 800px, 100vw"`が出ました。`responsiveStyles`は既定`false`で、`srcset`の生成とは関係ありません。画像のはみ出しを防ぐCSSを付けるかどうかの設定です。7.0.1からは、このCSSが`@layer astro.images`で包まれ、自分で書いた`@layer`のスタイルより優先度が下がりました。

## ファーストビュー画像のpriority指定とpreload

LCP（ページ内で最も大きい要素が表示されるまでの時間）の対象がヒーロー画像の場合、その画像の取得を早めると数値が改善します。指標の基準値は[Core Web Vitalsとは：LCP・INP・CLSの基準値とweb-vitals・CrUX APIでの測り方【2026年10月】](/tech/details/18645/)で整理しています。Astroで使える手段は、手間の少ない順に次の3つです。

### priorityによる読み込み属性の一括指定

5.10.0で`<Image>`と`<Picture>`に`priority`が追加されました。付けると`loading="eager"`・`decoding="sync"`・`fetchpriority="high"`が一度に入ります（[astro:assetsのAPIリファレンス](https://docs.astro.build/en/reference/modules/astro-assets/)）。

```
<Image src={photo} alt="山の写真" width={800} priority />

<!-- 出力 -->
<img src="/_astro/photo.4_AuFKfq_ZCIKgX.webp" alt="山の写真" loading="eager" decoding="sync" fetchpriority="high" width="800" height="450">
```

既定の`<Image>`は`loading="lazy"`です。LCPの画像に遅延読み込みが付いたままだと、ChromeのLCPリクエスト検出のインサイトは「LCP resources shouldn’t use loading=lazy」と指摘します。ファーストビューの1〜2枚にだけ`priority`を付け、それ以外は既定のままにします。

### getImageによるpreload用URLの生成

`<img>`がHTMLに書かれていれば、ブラウザはHTMLを読み進める途中でその画像を見つけます。preloadが効くのは、CSSの`background-image`やJSで後から差し込む画像のように、HTMLを読んでも見つからない画像です。この場合は`getImage()`で最適化済みのURLを作り、`<head>`にpreloadを書きます。

```
---
// src/pages/index.astro
import { getImage } from "astro:assets";
import Layout from "../layouts/Layout.astro";
import hero from "../assets/hero.png";

const bg = await getImage({ src: hero, format: "webp", width: 1600 });
---
<Layout>
  <link slot="head" rel="preload" as="image" href={bg.src} fetchpriority="high" />
  <section class="hero" style={`background-image: url(${bg.src})`}>...</section>
</Layout>
```

```
---
// src/layouts/Layout.astro：名前付きスロットで head に差し込む
---
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <slot name="head" />
  </head>
  <body><slot /></body>
</html>
```

preloadの`<link>`にも`fetchpriority="high"`を付けます。ChromeのLCPリクエスト検出のインサイトには「fetchpriority=high should be applied to the image preload request」という判定項目があり、preloadしただけでは優先度が上がりきらないためです（[Chrome DevToolsのLCPリクエスト検出の解説](https://developer.chrome.com/docs/performance/insights/lcp-discovery)）。preloadしたURLと実際に表示するURLが1文字でも違えば、同じ画像を2回ダウンロードすることになります。ビルド後に`dist`のHTMLを開き、`href`と`src`が同じファイル名か確かめてください。

### layout付き画像をpreloadするとURLがずれる理由

レスポンシブ画像をpreloadするときは、`<link>`の`imagesrcset`と`imagesizes`に`<img>`と同じ値を入れます（[web.devのレスポンシブ画像のpreload解説](https://web.dev/articles/preload-responsive-images)）。ここで`getImage()`に`layout: "constrained"`だけ渡すと、`<Image layout="constrained">`とは別のファイル群ができました。7.4.4で同じ元画像・幅800をビルドした結果です。

| 呼び出し                          | 800wのファイル名（末尾） | Imageと一致 |
| ----------------------------- | -------------- | -------- |
| <Image layout=”constrained”>  | \_ZjyR55.webp  | －        |
| getImage（layoutのみ）            | \_ZAYj8n.webp  | しない      |
| getImage（layout＋fit＋position） | \_ZjyR55.webp  | する       |

原因は`Image.astro`の既定値にあります。`layout`が`none`以外のとき、コンポーネントは`fit`に`"cover"`、`position`に`"center"`を自動で入れます（設定の`image.objectFit`・`image.objectPosition`があればその値）。`getImage()`はこの補完をしないので、変換パラメータが変わり、ファイル名のハッシュも変わります。preload側に同じ値を明示すれば一致します。

```
---
import { Image, getImage } from "astro:assets";
import hero from "../assets/hero.png";
import Layout from "../layouts/Layout.astro"; // 前節の Layout（head スロット付き）

// Image コンポーネントが自動で補う fit と position を明示する
const opts = { src: hero, width: 800, layout: "constrained", fit: "cover", position: "center" } as const;
const pre = await getImage(opts);
---
<Layout>
<link slot="head" rel="preload" as="image" href={pre.src}
  imagesrcset={pre.srcSet.attribute} imagesizes={pre.attributes.sizes} fetchpriority="high" />

<Image {...opts} alt="山の写真" priority />
</Layout>
```

確実なのは、preloadと表示を同じ`getImage()`の結果から作ることです。`<img src={pre.src} srcset={pre.srcSet.attribute} {...pre.attributes} alt="山の写真" loading="eager" fetchpriority="high">`と書けば、URLがずれる余地がありません。`image.objectFit`を設定で変えている場合は、その値を`fit`に渡します。

### Pictureでpreloadよりpriorityを優先する理由

`<Picture>`の画像はpreloadしない方が安全です。`<picture>`はブラウザが対応形式（`type`）を見て`<source>`を選びますが、preloadではこの選択を表現できません。web.devも、形式を切り替える`<picture>`ではpreloadを避け、priority hints（`fetchpriority`）を使うよう勧めています。形式を決め打ちしてpreloadすると、ブラウザが別の形式を選んだときに使われないファイルまで取得します。`<Picture priority>`なら、フォールバックの`<img>`に`fetchpriority="high"`が付き、ブラウザが選んだ形式だけが優先されます。

## Fonts APIによるWebフォントのpreload設定

「astro preload」で探している人のもう一つの用途がWebフォントです。Astro 6.0でFonts API（設定の`fonts`）が実験機能から正式機能になり、`@font-face`の生成、フォールバック、preloadをAstroが出力するようになりました。preloadは`<Font>`コンポーネントの`preload`で指定し、既定は`false`です。

```
// astro.config.mjs
import { defineConfig, fontProviders } from "astro/config";

export default defineConfig({
  fonts: [{
    provider: fontProviders.local(),
    name: "Inter",
    cssVariable: "--font-inter",
    options: {
      variants: [
        { src: ["./src/fonts/inter-latin-400-normal.woff2"], weight: 400, style: "normal" },
        { src: ["./src/fonts/inter-latin-700-normal.woff2"], weight: 700, style: "normal" },
      ],
    },
  }],
});
```

```
---
// src/layouts/Layout.astro の head
import { Font } from "astro:assets";
---
<!-- 400だけpreloadする（preload だけ書くと 400 と 700 の2本） -->
<Font cssVariable="--font-inter" preload={[{ weight: 400 }]} />

<!-- 出力 -->
<link rel="preload" href="/_astro/fonts/2605f035fc379c64.woff2" as="font" type="font/woff2" crossorigin>
```

`preload`だけを書くと、登録した2本のwoff2がどちらもpreloadされました。[Astro公式のフォントガイド](https://docs.astro.build/ja/guides/fonts/)も、preloadは他の重要なリソースの取得を妨げるので、ファーストビューの表示に要るフォントだけに絞るよう書いています。表示に使う要素には、別途CSSで`font-family: var(--font-inter);`を指定します。preloadする太さはファーストビューの内容で決めます。大きな見出しがLCP要素になるページでは、その見出し用の太字も候補にします。日本語フォントは1ファイルが数MBになることがあり、丸ごとpreloadするとLCPがかえって遅れます。

## prefetchによる遷移先ページの先読み設定

preloadが「このページで使うリソース」を先に取るのに対し、prefetchは「次に開きそうなページ」のHTMLを先に取得しておく仕組みです。Astroでは設定で`prefetch: true`にすると、`data-astro-prefetch`を付けたリンクが対象になります。各ページに入るスクリプトは、今回の検証構成で2,478バイトでした。

```
// astro.config.mjs
export default defineConfig({
  prefetch: {
    prefetchAll: false,
    defaultStrategy: "hover",
  },
});

<!-- リンクごとに戦略を指定する -->
<a href="/pricing/" data-astro-prefetch>料金</a>
<a href="/docs/" data-astro-prefetch="viewport">ドキュメント</a>
<a href="/contact/" data-astro-prefetch="false">問い合わせ</a>
```

### 4つの戦略が取得を始めるタイミング

7.4.4のprefetchスクリプトを読むと、戦略ごとの動きは次のとおりです。

| 戦略        | 取得を始めるきっかけ              | 向く場面          |
| --------- | ----------------------- | ------------- |
| hover（既定） | マウスが乗るかフォーカスして80ms後     | 通常のナビゲーション    |
| tap       | touchstart・mousedownの直後 | リンクが多い一覧      |
| viewport  | 画面に入って300ms後            | スマホで次に読む記事    |
| load      | ページ読み込み時にload対象リンク      | リンクが数本の小さなサイト |

回線の節約モード（`saveData`）や2G回線と判定されたときは、先読み対象のリンクは`tap`戦略にフォールバックし、タップ時に取得します。`load`をページ数の多いサイトで使うと、読まれないページまで取得してサーバーの転送量が増えます。

### ClientRouter使用時の既定とSafariの扱い

ページ遷移アニメーション用の`<ClientRouter />`を置いたページでは、prefetchが自動で有効になり、`prefetchAll: true`（全リンクが対象）が既定になります。対象を絞りたいときは設定で`prefetchAll: false`を明示します。

Safariは`<link rel="prefetch">`に対応していないため、Astroは`fetch()`で取得します。[Astro公式のprefetchガイド](https://docs.astro.build/ja/guides/prefetch/)によれば、この場合は`Cache-Control`・`Expires`・`ETag`のいずれかのキャッシュヘッダーが無いと、取得したHTMLが遷移時に使われません。ホスティング側でHTMLに`no-store`を付けているサイトでは、Safariでは効かないと考えてください。なお、`prefetch()`関数の`eagerness`オプションは`experimental.clientPrerender`を有効にしたときだけ使われ、7.4.4でも実験機能のままです。

## 画像サービスの選択とビルド時間の管理

「astro image service」は、画像を実際に変換する部品のことです。既定はsharpで、`image.service`で差し替えます。画像が多いサイトでは、画質よりもビルド時間が先に問題になります。

### sharpとpassthroughImageServiceの使い分け

sharpが動かない実行環境（公式ガイドの例ではCloudflare）でオンデマンド描画をする場合は、変換をしない`passthroughImageService()`に切り替えます。変換はされませんが、`<Image>`の幅・高さの自動付与と`alt`の必須チェックは残ります。

```
// astro.config.mjs
import { defineConfig, passthroughImageService } from "astro/config";

export default defineConfig({
  image: {
    service: passthroughImageService(),
  },
});
```

### 画像キャッシュの再利用と–timingsによる時間計測

Astroは変換済みの画像を`cacheDir`（既定は`./node_modules/.astro`）に保存し、次のビルドで使い回します。今回の検証では、20件の画像変換がキャッシュ無しで2.56秒、キャッシュ有りで22ミリ秒でした。CIで毎回`node_modules`を作り直していると、この効果が消えます。GitHub Actionsなら`node_modules/.astro`をキャッシュ対象に入れておきます。

7.4.0で追加された`astro build --timings`を付けると、ビルドの最後に画像変換・ページ描画・コンパイルの時間が一覧で出ます。画像が遅いと分かれば、`formats`を減らす、`layout`の`widths`を絞る、フォールバックPNGをやめる、の順に効きます。たとえば`<Picture layout="constrained" formats={["avif", "webp"]}>`をPNGフォールバックのまま使うと、1枚の元画像からAVIF・WebP・PNGが7本ずつ、計21ファイル生成されました。

## PageSpeed Insightsの点数と実ユーザー指標の優先順位

PageSpeed Insightsのラボスコアは、Lighthouse 13.6.0の設定でTBT 30・LCP 25・CLS 25・FCP 10・Speed Index 10の重み付けです（[Lighthouseの既定設定ファイル](https://github.com/GoogleChrome/lighthouse/blob/v13.6.0/core/config/default-config.js)）。INPは重み0で、点数に入りません。Astroはクライアント側JSを抑えやすい構成ですが、スコアは画像・フォントに加え、サーバー応答、CSS、追加したJSなどにも左右されます。priority・preload・画像形式の調整は主にLCPの改善候補です。画像によるCLSには、width・heightやCSSのaspect-ratioによる表示領域の確保で対処します。各カテゴリの配点の読み方は[LighthouseのSEOスコア・Best Practicesの配点と見方｜5カテゴリの採点基準【v13.5.0】](/column/details/2354/)で解説しています。

100点そのものを目標にする必要はありません。Googleは[ページエクスペリエンスの解説](https://developers.google.com/search/docs/appearance/page-experience)で「There is no single signal.」と書き、ページエクスペリエンスが劣っていても関連性の高いコンテンツを表示するとしています。Search ConsoleのCore Web Vitalsレポートが使うのも実ユーザーのデータ（CrUX）で、ラボの点数ではありません。90点台からさらに上げる作業より、実際のアクセスでLCPとINPが「良好」に入っているかを確認する方が先です。INPの改善手順は[INPとは？Core Web Vitalsの応答性指標の基準値と3区間・改善手順](/tech/details/7543/)にまとめています。

次の場面では、Astro側の調整より先に別の原因を疑います。サーバーの応答（TTFB）が遅い、広告やタグマネージャーのJSが重い、ヒーロー画像を外部CMSから毎回取得している、のいずれかです。サイト全体を効き目の順に直す手順は[サイトの表示速度を改善する手順：画像・キャッシュ・JS・サーバーを効き目順に直す【2026年10月】](/tech/details/18974/)を参照してください。既存サイトをAstroで作り直して表示速度を上げたい場合は、[Webサイトリニューアル](/service/web/renewal/)としてご相談いただけます。

## よくある質問

### npmのastro-preloadパッケージとAstroのpreloadは同じものですか？

別物です。[astro-preload](https://github.com/lyonsyonii/astro-preload)は、リモートの画像やIconifyのアイコンをビルド時にダウンロードして`public/`に保存する第三者製のインテグレーションです。npmで公開されている最新版は1.1.2（2023年7月1日公開）で、それ以降の版はnpmに出ていません。`<link rel="preload">`を出すものではないので、LCP対策には`priority`か`getImage()`を使います。

### publicフォルダの画像も最適化されますか？

されません。`public/`のファイルはそのままビルド結果にコピーされます。最適化したい画像は`src/assets/`などに移してimportし、`<Image>`に渡してください。faviconやOGP画像のように、URLを固定したいファイルだけを`public/`に残します。

### preloadとprefetchはどう使い分けますか？

preloadは表示中のページで必ず使うリソース（ヒーロー画像・本文フォント）を高い優先度で先に取得します。prefetchは次に開くかもしれないページを低い優先度で取得します。preloadを付けすぎると本当に必要なリソースの取得が遅れ、prefetchを付けすぎると読まれないページの転送が増えます。

### @astrojs/imageはまだ使えますか？

使えません。`@astrojs/image`は0.18.0でnpm上の非推奨になり、「deprecated in favor of astro:assets」と表示されます。Astro 3.0以降は`astro:assets`が標準で、`npx astro add image`を前提にした古い手順は今の版では動きません。

### Astro 7へ上げるとき画像まわりで注意する点はありますか？

7.0.1でレスポンシブ画像のCSSが`@layer astro.images`で包まれました。自分のCSSを`@layer`で書いている場合、以前は負けていたスタイルが勝つようになり、画像のサイズや配置が変わることがあります。上げたあとはファーストビューの画像の表示を確認してください。`priority`と`layout`は5.10.0から使えるので、5系の後半から上げる場合は書き換えは要りません。

## 関連記事

- [Astroフレームワークとは？特徴と使い方・Next.jsとの使い分けを解説【2026年版】](/tech/details/15369/)
- [AstroとReactの違いと使い分け｜AstroでReactを使う方法【Astro 7対応】](/tech/details/2697/)
- [アイランドアーキテクチャとは？仕組みとAstro 7の実装・JS量の実測、PPRとの違い](/tech/details/2423/)
- [Astro 5の新機能と移行手順｜Content Layer・Server Islands・hybrid廃止をビルドで検証](/tech/details/10386/)
- [Lighthouse CIの使い方｜lighthouserc・assertの判定とGitHub Actions連携【@lhci/cli 0.15.1】](/tech/details/7542/)

---

出典: [Astroの画像最適化とpreload・prefetch｜astro:assetsの実装【Astro 7.4】](<https://www.issoh.co.jp/tech/details/2762/>)（株式会社一創）
