🌊

AstroのPictureコンポーネントを自作した

2024/01/29に公開

最近プロジェクトでAstroを使っていて、画像の最適化で色々調査して結果的に自作することになりました。

実現したいこと

スクラップの記事にも書いたのですが、

  • 画像の最適化をしたい。(jpgやpngをwebpに変換してほしい)
  • pictureタグで画面幅に合わせて画像を出し分けしたい。
<picture>
  <source srcset="画像のパス" media="(min-width: 1024px)">
  <img src="画像のパス" alt=”代替テキスト”>
</picture>
  • 背景画像も最適化の対象としたい。
  • ビルド時に最適化処理したい。
  • 画像ディレクトリは一緒にしたい。

Astro公式のPictureコンポーネント

Astro v4.2時点ではImageコンポーネントとPictureコンポーネントが定義されているが、背景画像や画面幅での出しわけができない。
https://docs.astro.build/ja/guides/images/

自作したPictureコンポーネント

getImage関数を使って画像を最適化しています。
https://docs.astro.build/ja/guides/images/#getimageで画像を生成する

MIN_WIDTH_MDは"(min-width: 960px)";を定数として定義しているものです。
pngやjpgのフォールバックはありませんが、渡ってきたpropsには入っていますので必要であれば対応できます。

---
import { getImage } from 'astro:assets';
import type { HTMLAttributes } from 'astro/types';
import { MIN_WIDTH_MD } from '~/data/siteData';
interface Props extends HTMLAttributes<'img'> {
  imgSrc: ImageMetadata;
  imgSrcPC?: ImageMetadata;
}

const { imgSrc, imgSrcPC, ...attrs } = Astro.props;
const optimizedImage = await getImage({ src: imgSrc, format: 'webp' });
const optimizedPCImage = imgSrcPC && (await getImage({ src: imgSrcPC, format: 'webp' }));
---

<picture>
  {imgSrcPC && <source media={MIN_WIDTH_MD} srcset={optimizedPCImage?.src} />}
  <img src={optimizedImage.src} {...attrs} />
</picture>

こんな感じで使います。

---
import Picture from '~/components/atomic/Picture.astro';
import largeImage from '~/images/imgpc.png';
import smallImage from '~/images/img.png';
---
<Picture imgSrc={smallImage} imgSrcPC={largeImage} alt="" />

この勢いで背景画像もどうにかできないか模索していきます。

TAM

Discussion