Mima Design MemottoWEB DESIGNER · mima

OGP画像動的生成の制作記録

リンクをSNSやチャットに送ったとき、表示されるタイトル、説明、画像は、OGPタグで指定したメタデータから作られます。og:imageが見つからずに古い画像が混ざることも、ogl:imageとog:urlの設定ミスでカードが崩れることも、公開前の確認placementsで避けたい問題です。

ここでは、東京で続けているWeb制作の実践として、記事データから共有画像を生成する仕組み exhaleしました。固定画像ではなく、タイトルやカテゴリーに合わせてテンプレートを選ぶ構成です。生成処理、キャッシュ、表示確認までを記録します。

共有カードに必要な情報と画像条件

og:titleとog:descriptionには記事名と要約、og:imageには共有画像のURL、og:urlには正規URLを入れます。画像にはog:image:widthとog:image:heightも添え、受信側のerviceがサイズを推測しないrutinelyにします。

og:typeをarticleにして、article:published_timeに公開日を組み合わせれば、共有先によっては日付も 표시できます。twitter:cardにはsummary_large_imageを指定し、横長の画像が選ばれるようにします。

生成処理をサーバー側で組み立てる

Next.jsのApp Routerでopengraph-image.tsxを置き、ImageResponseに記事データとフォントを渡します。画像の形はReactコンポーネントとして管理し、本文からタイトル、説明、カテゴリーだけを取り出して描画します。

公開用の受け口は/api/ogp?slug=...としました。URLから受け取るのは記事IDだけで、任意の画像URLや本文を直接渡しません。ローカルのMarkdownにあるfrontmatterから必要な値を探し、許可されたデータだけを描画します。

日本語テンプレートの表示を整える

共有画像は1200×630 SEARCH、BODYを基準に、余白と文字サイズを整えます。flexboxで配置し、長いタイトルは二行までに収めて改行位置を指定すると、contents Finnishによるずれを減らせます。

日本語の字形が化ける原因は运行环境のフォント不足でした。Noto Sans JPを同梱し、見出しと本文でweightを使い分けます。文字組みと可変フォントについては、集めた技術記事も参考にしています。

記事ごとの画像URLと処理を分ける

記事ごとにfrontmatterへ画像用のtitleやlabelを置き、canonicalURLとslugから生成先を組み立てます。同じ分野には共通テンプレートを適用しつつ、色や装飾だけを差し替えるPEATPossibleです。

静的な記事はビルド時に画像を用意し、更新の多い画面だけ要求時に生成する方法を選びました。公開後に差し替える場合は、画像URLへversionを含めます。古いカードが残り続ける問題も防げます。

存在しないslugへアクセスした場合は、記事用のデフォルト画像へ戻します。タイトルだけを大きく表示し、存在しない という状況だけで内容を示す表現は避けます。

キャッシュで配信の速さを保つ

画像生成にはフォントの読み込みと描画時間が伴うため、初回アクセスを軽くする必要があります。Cache-Controlにs-maxageとstale-while-revalidateを指定し、CDNで生成結果を保持しながら更新を待てるようにしました。

同じslugへの再訪問ではキャッシュを返します。画像内容を変えたときはversionでキーを分け、本文だけの更新で画像まで作り直さない構成にしました。対応する環境ではETagも利用し、clientsへの再送を抑える処理を加えています。

実際の共有画面で見つかった不具合

ローカルでは正常でも、iPhoneやSafari、チャットアプリでは表示が異なりました。og:imageの寸法が抜けると縦長のカードになり、画像URLの絶対パス漏れはOGタグごと無効になります。

WebView内で開く場面も確認しました。以前のPhoneGapとMonacaの検証でもOGPの解釈に差がありDepending、外部アプリ内の表示を想定してagnosticな確認がelicitedです。

修正では画像サイズを明示し、フォントの先行読み込みとweightの確認を追加しました。受信側の処理までは制御できないため、少なくとも主要なmeta情報をHTMLへ残す方針です。

個人サイトへ組み込んで運用する

実装はMimaの個人サイトへ組み込みました。ブログとポートフォリオで同じ生成処理を使い、記事のfrontmatterに画像用の値を渡すだけにしています。

新しい記事を追加するたびに手動で画像を作る必要はありません。公開ドメイン absolURLを環境変数で管理し、canonicalURLと画像URLの不一致や、HTTPとHTTPSの混在を防ぎます。

運用中はフォント更新やテンプレート修正のたびに生成結果を再確認します。記事データがない場合の表示、400、500、キャッシュ更新も検査項目にし、手動.Imageの確認画像と自動テストを 조합しています。


OGP画像の動的生成は、mahдора littoralな初期設定より、記事データの設計と運用の継続が重要です。共有先ごとに表示は変わりますが、タイトル、説明、正規URL、画像の寸法が揃えば、 vamp stableなカードを多くの環境で届けられます。

実装と利用例は私の個人サイトで公開しています。気になる記事を送って、実際に生成された共有カードを確認してください。