Astroでの画像の取り扱いについて

爆速静的サイトジェネレーター「Astro」での、基本的な画像の取り扱いと、便利な画像最適化の手法についてまとめてみました。

この記事は、Astroのバージョン2.1.4に対応しています。

Astroのインストール

npmでAstroのプロジェクトを作成します。

# npmで新しいプロジェクトを作成する
npm create astro@latest

インストールガイドの中で、Include sample filesを選択し、以下のような構成でAstroが展開された状態になっているとします(一部省略)。
(以後、TypeScriptを使用している前提で説明していきます)

astro-project/
├── astro.config.mjs
├── node_modules
├── package.json
├── public
├── src
│    ├── layout
│    │     └── Layout.astro
│    ├── pages
│    │     └── index.astro
│    └── env.d.ts
└── tsconfig.json

画像の表示方法3選

Astroでは、ページ内に画像を表示するのに複数の手段があるため、Webページ用の挿絵としては少しヘビーな以下の画像を使ってそれぞれの手法を検証します。

検証用画像:

ファイル名:sample.jpg
画像サイズ:2048px × 1533px
画像形式:JPEG
画像容量:647KB

publicディレクトリとimgタグを使用する

publicディレクトリの中にimagesというディレクトリを作成し、その中にsample.jpgを配置します。

astro-project/
├── node_modules
├── public
│    └── images
│          └──sample.jpg
├── src
│    ├── layout
│    │     └── Layout.astro
│    ├── pages
│    │     └── index.astro

続いて、pages/index.astroに通常のimgタグを記述し、publicディレクトリ内のsample.jpgを指定します。
このとき、imgのsrcpublicディレクトリから見た相対パスにします。

---
import Layout from '../layouts/Layout.astro';
---
<Layout title="Astroでの画像の表示方法">
  <img src="/images/sample.jpg" alt="Sample" />
</Layout>

<style>
  img {
    max-width: 100%;
    height: auto;
  }
</style>

ここまで記述したら、

npm run dev

で、画像が表示されていることを確かめてみましょう。

画像が正しく表示されていたら、

npm run build

で、Astroをビルドすると、distディレクトリ内に静的ファイル一式が生成されます。

astro-project/
├── node_modules
├── dist
│    ├── _astro
│    ├── images
│    │     └──sample.jpg
│    └── index.html
├── public
└── src

先ほどpublic/images/sample.jpgに配置した画像は、dist/images/sample.jpgとして展開されています。展開後の画像情報を見ると、画像サイズも容量も同じ状態でコピーされていることがわかります。

ファイル名:sample.jpg
画像サイズ:2048px × 1533px
画像形式:JPEG
画像容量:647KB

このように、public配下に配置したファイルは画像を含め、ビルド後に(Astroによる最適化の処理をされずに)distディレクトリにそのまま展開されるため、深く考えずにimgタグによる記述で画像を表示することができます。

srcディレクトリとimgタグを使用する

次に、astroファイルなどと同じ、srcディレクトリに画像を配置して表示するパターンです。

srcディレクトリの中にimagesというディレクトリを作成し、その中にsample.jpgを配置します。

astro-project/
├── node_modules
├── public
├── src
│    ├── images
│    │     └──sample.jpg
│    ├── layout
│    │     └── Layout.astro
│    ├── pages
│    │     └── index.astro

この状態で、pages/index.astrosrc/images/sample.jpgをimportして利用することができます。
(importするパスは、astroファイルから見た相対パスになります)

index.astro側には、先ほどと同じくimgタグで、importした画像をsrcとして記述します。

---
import Layout from '../layouts/Layout.astro';
import localImage from '../images/sample.jpg';
---
<Layout title="Astroでの画像の表示方法">
  <img src={localImage} alt="Sample" />
</Layout>

<style>
  img {
    max-width: 100%;
    height: auto;
  }
</style>

プレビューすると先ほどと同じく画像が表示されます。

これをビルドすると、

astro-project/
├── node_modules
├── dist
│    ├── _astro
│    │     ├──index.10c61ba9.css
│    │     └──sample.a9447241.jpg
│    └── index.html
├── public
└── src

dist/_astroディレクトリに画像が展開されます(このとき、srcディレクトリ内での画像が配置された階層に関係なく、_astro直下に展開されるようです)。展開後の画像は、ファイル名は自動的に一意のものに変換されますが、サイズや画像形式、容量は同一となっています。

ファイル名:sample.a9447241.jpg
画像サイズ:2048px × 1533px
画像形式:JPEG
画像容量:647KB

正直言うと、このやり方をするくらいなら、先のpublicディレクトリを使った手法か、後述する画像インテグレーションを使用したほうが良いと思います。

Astro画像インテグレーションを使用する

最後に、Astro画像インテグレーションを使って、画像の最適化を行う方法です。
まず、以下のように@astrojs/imageをクイックインストールします。

npx astro add image

@astrojs/imageをクイックインストールすると、astro.config.mjsにインテグレーションの記述が自動的に追加されます。

astro.config.mjs

import { defineConfig } from 'astro/config';
import image from "@astrojs/image";

// https://astro.build/config
export default defineConfig({
  integrations: [image()]
});

続いて、env.d.tsにおいて@astrojs/imageを使用する際に必要な型情報に差し替えます。

env.d.ts

// <reference types="astro/client" />
/// <reference types="@astrojs/image/client" />

そして、srcディレクトリの中にimagesというディレクトリを作成し、その中にsample.jpgを配置します。

astro-project/
├── node_modules
├── public
├── src
│    ├── images
│    │     └──sample.jpg
│    ├── layout
│    │     └── Layout.astro
│    ├── pages
│    │     └── index.astro

index.astro側は、@astrojs/image/componentsからImageコンポーネントをimpotしておきます(1行目)。そしてsrcディレクトリの画像を相対パスでimpotし、imgタグではなくImageを使って記述します。

---
import { Image } from '@astrojs/image/components';
import Layout from '../layouts/Layout.astro';
import localImage from '../images/sample.jpg';
---
<Layout title="Astroでの画像の表示方法">
  <Image src={localImage} alt="Sample" />
</Layout>

<style>
  img {
    max-width: 100%;
    height: auto;
  }
</style>

これをビルドすると、

astro-project/
├── node_modules
├── dist
│    ├── _astro
│    │     ├──index.10c61ba9.css
│    │     └──sample.a9447241_ZWbci4.jpg
│    │     └──sample.a9447241.jpg
│    └── index.html
├── public
└── src

dist/_astroディレクトリに元画像(sample.a9447241.jpg)の他に、最適化された画像(sample.a9447241_ZWbci4.jpg)が展開されます。最適化された画像は、サイズと画像形式は同じですが、容量が低下しています。

ファイル名:sample.a9447241_ZWbci4.jpg
画像サイズ:2048px × 1533px
画像形式:JPEG
画像容量:258KB

HTMLのソースコードは、以下のようにimgタグにwidthとheightが自動的に追加され、loading="lazy"decoding="async"属性が追加された状態になります。

<img src="/images/sample.jpg" alt="Sample" class="astro-J7PV25F6"><img alt="Sample" class="astro-J7PV25F6" width="2048" height="1533" src="/_astro/sample.a9447241_ZWbci4.jpg" loading="lazy" decoding="async">

また、Imageコンポーネントにはいくつかのオプションがあり、代表的なものは以下になります。

width(height)を指定する

<Image src={localImage} alt="Sample" width={800} />

width、もしくはheightを指定するとHTMLのコード上だけではなく、ビルド後の画像サイズが変わります。

ファイル名:sample.a9447241_Z10eWMh.jpg
画像サイズ:800px × 599px
画像形式:JPEG
画像容量:41KB

formatを指定する

<Image src={localImage} alt="Sample" format="webp" />

format(画像形式)を指定することで、以下のような形式に変換することができます。
(ビットマップ画像からsvgへの変換はできない)

‘avif’ | ‘jpeg’ | ‘jpg’ | ‘png’ | ‘svg’ | ‘webp’

ファイル名:sample.a9447241_1mDded.webp
画像サイズ:2048px × 1533px
画像形式:WebP
画像容量:254KB

qualityを指定する

<Image src={localImage} alt="Sample" width={960} format="webp" quality={80} />

qualityを数値で指定することで、画像の圧縮率を変えることができます(数値が高いほうが圧縮率が低い)。

ファイル名:sample.a9447241_Z1T1pgr.webp
画像サイズ:960px × 719px
画像形式:WebP
画像容量:66KB

まとめ

Astroでは、大きく分けて以下の3つの画像の表示方法があり、それぞれの特徴を持っています。

  • publicディレクトリに画像を配置して、imgタグで表示する
    (自分で最適化済みの画像を用意するなら最もお手軽、LP構築などに良いかも)
  • srcディレクトリに画像を配置して、imgタグで表示する
    (画像をimportする必要があるのと、最適化もされないのであまり使わない)
  • @astro/imageを使って画像を最適化する
    (適当に用意した画像をフロントエンド側で最適化できるため、HeadlessCMS構築などに良いかも)

@astro/imageは、sharpパッケージを使った画像変換オプションや、pictureによる画像の出し分け機能もあるため、また別途詳しくご紹介します。

Twitterでシェアする