【Gatsby】GIF画像のサイズを指定する

【Gatsby】GIF画像のサイズを指定する

はじめに

今回は記事内に設置した GIF 画像のサイズを画面幅に応じて変更する方法について解説します。

事の経緯

以前まで記事内の GIF 画像は gatsby-remark-gifs-to-videos というプラグインを使用してビルド時に MP4 に変換するようにしていました。

しかし、本番環境デプロイ時に(Github Actions を使用)なぜが MP4 動画に変換されない GIF 画像があることに気が付きました。

Github のIssuesを見ても特にそのような問題は報告されておらず、仕方ないのでプラグインの使用を辞めて直接 GIF 画像を出力するようにしました。

width 100% で出力される GIF 画像

gatsby-remark-copy-linked-files によって記事内に設置した GIF 画像はビルド時にpublicフォルダにコピーされるようにしています。

GIF 画像のファイルパスは img タグの src 属性に指定されるため、png 等の他の画像ファイルと同様にwidth: 100%;で出力されており、元の GIF 画像のサイズが小さい場合は以下のようにかなり拡大されて出力されます(PC で表示時)

full-gif-image.png

そこで、GIF 画像のスタイルを画面幅に応じてしてするコンポーネントを作成して以下のように GIF 画像のサイズを変更するようにしました。

※PC の画面幅 pc-size.png

※スマートフォンの画面幅 mobile-size.png

ビジュアルを持たないコンポーネントを作成

app-style-gif-images.jsxという HTML を返さないコンポーネントを作成します。

"app-style-gif-images.jsx"
import { useEffect } from 'react';

const ApplyStyleToGifImages = () => {
  useEffect(() => {
    // 画面幅がタブレットサイズかどうかをチェックする関数
    const isTabletWidth = width => width <= 768;

    // すべてのimgタグを取得し、GIF画像に対してスタイルを適用する関数
    const applyStyleToGifImages = () => {
      const images = document.querySelectorAll('img');
      images.forEach(img => {
        if (img.src.endsWith('.gif')) {
          // スタイルをオブジェクトとして定義
          const style = isTabletWidth(window.innerWidth)
            ? {
                width: '100%',
              }
            : {
                width: 'auto',
                margin: '0 auto',
                display: 'block',
                maxWidth: '100%',
                maxHeight: '100%',
              };

          // オブジェクトのキーをループしてスタイルを適用
          Object.keys(style).forEach(key => {
            img.style[key] = style[key];
          });
        }
      });
    };

    // 初回実行と画面サイズ変更時にスタイルを適用
    applyStyleToGifImages();
    window.addEventListener('resize', applyStyleToGifImages);

    // コンポーネントがアンマウントされる時にイベントリスナーを削除
    return () => window.removeEventListener('resize', applyStyleToGifImages);
  }, []); // 空の依存配列を渡して、コンポーネントのマウント時にのみ実行されるようにする

  return null; // このコンポーネントはビジュアルを持たない
};

export default ApplyStyleToGifImages;

実行していることは、endsWithメソッドを使用して画像ファイルの拡張子が.gifの場合に指定したスタイルを当てるシンプルなものです。

上記のコンポーネントをブログ記事のテンプレートに設置します(blog-post.jsx

"blog-post.jsx"
// 省略

// 記事内のGIF画像をリサイズするコンポーネント
import ApplyStyleToGifImages from '../components/app-style-gif-images'

const BlogPostTemplate = ({ pageContext, data, location }) => {

    // 省略

  return (
    <Layout
      location={location}
      title={siteTitle}
    >
      {/* GIF画像にスタイルを適用するコンポーネント */}
      {/* ビジュアルを持たないコンポーネントなので、配置はどこでも良い */}
      <ApplyStyleToGifImages />

      <Iframely />
      <Seo
        title={post.frontmatter.title}
        description={post.frontmatter.description || post.excerpt}
        img={ogpImg}
        location={location}
      />

以下のように画面幅に応じて GIF 画像もリサイズされます。

resize-gif-image.gif

(サイドバーのスタイルが…)

参考記事