はじめに
今回は記事内に設置した 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 で表示時)
そこで、GIF 画像のスタイルを画面幅に応じてしてするコンポ ーネントを作成して以下のように GIF 画像のサイズを変更するようにしました。
※PC の画面幅
※スマートフォンの画面幅
ビジュアルを持たないコンポーネントを作成
app-style-gif-images.jsx
という HTML を返さないコンポーネントを作成します。
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
)
// 省略
// 記事内の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 画像もリサイズされます。
(サイドバーのスタイルが…)