12k
All articles

アニメーションGIFをMP4動画に置き換える方法

アニメGIFをMP4またはWebM動画に置き換える方法を解説。autoplay muted loop playsinlineの書き方、ffmpeg変換、LCP対策も紹介。

OpenReplay Team
OpenReplay Team
アニメーションGIFをMP4動画に置き換える方法

アニメーションGIFを動画に置き換えるには、クリップをH.264のMP4とVP9のWebMに変換し、両方を <video autoplay muted loop playsinline> で埋め込み、WebMの <source> を先に記述します。

Lighthouseが製品ページやドキュメントでアニメーションコンテンツを指摘した場合、その原因はたいてい数メガバイトに達する画面録画GIFです。本記事では、GIFがサイズ面で不利になる理由、変換手順(ブラウザツールまたはffmpegのいずれか)、正確なマークアップ、この置き換えがLCPに与える影響、そしてGIFが依然として正しい選択肢となるケースについて解説します。

要点

  • アニメーションGIFは各フレームを最大256色のほぼ完全な画像として保存するため、動画コーデックが前提としているフレーム間圧縮の恩恵をまったく受けられません。
  • ブラウザが自動再生を許可する条件となるのが muted であり、iOSが動画を強制的にフルスクリーン化するのを防ぐのが playsinline です。
  • ブラウザは最小のものではなく、デコード可能な最初の <source> を再生するため、WebMのソースはMP4フォールバックより先に記述する必要があります。
  • Chrome 116以降、poster を持たない <video> はLCP要素になり得るようになり、記録される時刻は最初のフレームが画面に表示された瞬間です。
  • サイズ削減率はクリップの内容に完全に依存します。引用されたパーセンテージを鵜呑みにせず、自分のファイルで前後を計測してください。

なぜGIFはモーション表現に適さないコンテナなのか

アニメーションGIFはすべてのフレームを、1フレームあたり最大256色のパレットを持つほぼ完全な画像として保存します。そのため、動画フォーマットが前提として設計されたフレーム間圧縮の恩恵をまったく受けられず、さらにH.264やVP9が多くのデバイスでハードウェアデコード経路を持つのに対し、GIFはソフトウェアでデコードされます。GIF89a仕様書には、このフォーマットがアニメーションを扱うために作られたものではなく、限定的な形でのみ許容していると明記されています。ループ再生は後からブラウザによって追加されたものです。歴史的な経緯として知っておくべきことはこれで十分です。

実務上の帰結として、数秒の画面録画はGIFでは日常的に数メガバイト規模になり、動画では数百キロバイトに収まります。Lighthouseもこれを指摘しており、GIFから動画への変換に関する助言は、Lighthouse 13以降Improve image delivery insightの中に組み込まれています。

実際の変換例と実測値

Googleのこのトピックに関するweb.devガイドには、以下に示すのと同じコマンドで変換された、率直な事例が1つ公開されています。3.7 MBのソースGIFが551 KBのMP4と341 KBのWebMになりました。削減量はクリップの内容、フレームレート、寸法に完全に依存するため、あるファイルで計測されたパーセンテージがあなたのファイルに当てはまるとは限りません。

ファイルサイズ
ソースGIF3.7 MB
MP4 (H.264, CRF 25)551 KB
WebM (VP9, CRF 41)341 KB

これらの数値は法則ではなく、あくまで1つのデータポイントとして扱ってください。動きの激しい映像は、ほぼ静止したターミナル録画とは異なる圧縮特性を示します。実際に運用する前に、自分のクリップを以下の手順に通してバイト数を比較してください。

GIFを動画に置き換える方法: ファイルの作成

必要なファイルは2つです。あらゆる環境で再生できるMP4と、たいていはより小さくなるWebMです。各手順にはブラウザツールと、それに相当するffmpegコマンドを示します。

ステップ1: GIFからMP4へ。 ブラウザ内でローカルに動作するGIF to MP4 converter、またはffmpegを使用します:

ffmpeg -i input.gif -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" \
  -vcodec libx264 -pix_fmt yuv420p -b:v 0 -crf 25 -f mp4 output.mp4

-pix_fmt yuv420p はファイルをあらゆる環境で再生可能に保ちます。CRFは0から51の範囲を取り、値が低いほど高品質になります。-b:v 0 はCRFモードでビットレート制限を無効化します。crop フィルターは、libx264が奇数のピクセル寸法を受け付けないことに対するweb.devの回避策です。

ステップ2: WebMファイル(2番目の <source> 用)。ブラウザで行う場合は、作成したばかりのMP4をMP4 to WebM converterに読み込ませます。ffmpegの場合は、クリップが二重に圧縮されないよう、元のGIFから直接エンコードします:

ffmpeg -i input.gif -c:v libvpx-vp9 -b:v 0 -crf 41 output.webm

VP9のCRFスケールはx264のものとは異なるため、ここでの41は低品質設定ではなく妥当なデフォルト値です。

ステップ3: 任意のチューニング。 結果がまだ重い場合は、video compressorで解像度と品質を下げるか、ffmpegを使います:

ffmpeg -i output.mp4 -vf scale=640:-2 -crf 28 -movflags faststart smaller.mp4

-movflags faststart はMP4のメタデータをファイルの先頭に移動させ、ダウンロード完了前に再生を開始できるようにします。

GIFのように振る舞うマークアップ

動画をGIFのように振る舞わせるには、<video autoplay muted loop playsinline> を使います。ブラウザが自動再生を許可する条件となるのが muted であり、iOSが動画を強制的にフルスクリーン化するのを防ぐのが playsinline です。

<video autoplay muted loop playsinline width="640" height="360">
  <source src="clip.webm" type="video/webm">
  <source src="clip.mp4" type="video/mp4">
</video>

Chromeの自動再生ポリシーは、ミュートされた動画の自動開始を許可する一方、音声付きの自動再生は訪問者がサイトを操作するまで保留します。iOS向けWebKitの動画ポリシーは、ミュートされているか音声トラックを持たない場合に限り、ユーザー操作なしでの自動再生を許可しており、iPhoneでクリップをインライン再生するには playsinline が必要です。ブラウザは最適な<source>を選ぶわけではなく、デコード可能な最初のものを再生するため、ソースの順序が重要になります。したがって、より小さいWebMを先に置きます。この順序はどの環境でも安全です。caniuseのWebMテーブルによれば、macOSのSafari 16およびiOS 17.4以降のSafariで完全サポートされており、AppleとWebMに関する2018年頃の警告はもはや当てはまりません。widthheight 属性はレイアウト領域を予約するもので、画像に対して行うのと同じCLSへの配慮です。

これらの属性のいずれかが欠けていても、失敗は静かに起こります。コンソールエラーも壊れた画像アイコンも出ず、ただ最初のフレームが静止するだけです。セッションリプレイは各ユーザーが実際に見たとおりのページを示してくれるため、本番環境で開始されなかった自動再生動画を捕捉する唯一の信頼できる手段となります。

この置き換えはLargest Contentful Paintにどう影響するか

<img><video> に置き換えると、LCP候補になり得る要素が変わります。以前のガイダンスでは poster のない <video> はLCPから不可視だとされていましたが、Chrome 116でそれが変わりました。Chromiumのメトリクス変更履歴には、動画要素が画像と同じ扱いで対象となり、そのタイムスタンプは最初のフレームが画面に到達した瞬間から取得されると記録されています。したがって、メトリクスを操作する目的だけで poster を追加すべきではありません。自動再生される動画は最初のフレームを即座に描画するため、posterの画像は決して表示されません。ヒーローアニメーションが最大の要素である場合、そのLCPのタイミングは最初のフレームがどれだけ速く届くかに左右されます。これもファイルを小さく保つべきもう1つの理由です。

GIFが依然として優位なのはどんな場合か

マークアップを制御できない場面では、GIFが依然として優位です。チャットメッセージ、メールクライアント、GitHubのREADMEはGIFをインラインで表示しますが、自動再生される動画を埋め込むことはできません。こうした環境では、ページ重量よりも可搬性が優先され、正しい選択は変換ではなくGIFの非可逆圧縮です。gifsicle--lossy オプション(かつては別プロジェクトのgiflossy)は、アーティファクトと引き換えにサイズを削減します:

gifsicle -O3 --lossy=80 -o smaller.gif input.gif

lossy値を高くするほどアーティファクトが増え、ファイルは小さくなります。出力が許容できなくなるまで調整し、そこから少し戻してください。

まとめ

マークアップを制御できるページであれば、モーションはGIFではなく、2つのソースを持つ <video> 要素に収めるべきです。サイト内で最も重いGIFを1つ選び、上記の変換手順に通して、バイト数を自分で比較してください。そのうえで、WebMを先に置いた4属性のマークアップをデプロイし、実際のセッションのリプレイを確認して、正しく再生されていることを検証しましょう。

FAQ

MP4だけを配信してWebMファイルを省略できますか?

はい。yuv420pピクセルフォーマットのH.264 MP4は現代のあらゆるブラウザで再生できるため、単一ソースのvideo要素でもどこでも動作し、何も壊れません。WebM版はサイズ最適化であり、互換性の要件ではありません。VP9は通常、同等の品質でより小さいファイルを生成します。まずMP4をリリースし、ページ重量がまだ気になるようであれば、後からその上にWebMソースを追加してください。

autoplay、muted、loop、playsinlineを設定しているのに動画が自動再生されないのはなぜですか?

マークアップではなく、ユーザーエージェントのポリシーが再生をブロックしています。iOS Safariはデバイスが低電力モードのときに自動再生を停止し、代わりに再生ボタンを重ねて表示します。他のブラウザのバッテリー節約モードやデータ節約モードも同様に動作することがあります。JavaScriptで検出しましょう。video.play() はPromiseを返すので、rejectを処理して、静止したフレームの代わりにコントロールや静的なフォールバック画像を表示してください。

loading='lazy' はvideo要素で機能しますか?

Chromiumベースのブラウザでは機能します。Chrome、Edge、Operaは、lazy指定された動画のダウンロード、posterの取得、自動再生を、要素がビューポートに近づくまで遅延させます。MDNもこの属性を文書化しています。HTML仕様への対応する追加は進行中で、FirefoxとWebKitはいずれもこの機能に対して肯定的な標準化ポジションを表明していますが、まだ実装は出荷されていません。サポートしていないブラウザは単に属性を無視して即座に読み込むため、画面外にあるGIF置き換え動画にこれを追加することは現時点で安全です。

アニメーションWebPはGIFと動画の中間として良い選択肢ですか?

場合によります。アニメーションWebPは通常のimg要素の中で動作し、GIFの256色パレットではなく24ビットカラーをサポートし、通常は同等のGIFより小さいファイルを生成します。しかし、本物の動画コーデックには及びません。画面録画であればH.264やVP9のほうがはるかに高い圧縮率を発揮します。imgタグが必須でありながら現代的なフォーマットを受け入れる環境ではアニメーションWebPを使い、マークアップを制御できる場所では動画を使ってください。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.