當你滿心期待地在 Facebook 分享你的中文部落格文章,卻發現預覽圖只顯示「loading」或一堆亂碼方塊時,那種挫折感我完全理解。今天花了幾個小時,終於徹底解決了這個問題。
問題的根源
最初使用 og-image.vercel.app 來動態生成 Open Graph 圖片。對於英文內容來說,這個服務完美無瑕。但對於中文?完全不行。
問題有兩個層次:
Facebook 不執行 JavaScript 我的
post.html中的 OG meta tags 是由 JavaScript 動態填入的。Twitter/X 可以正常抓取,但 Facebook 的爬蟲只看到空白的<meta property="og:title" content="Loading">。og-image.vercel.app 不支援中文字型 即使預先填入 meta tags,使用
og-image.vercel.app生成的圖片也會將中文顯示為亂碼或方塊,因為預設字型不包含 CJK 字元集。
解決方案:Cloudinary + Noto Sans TC
為什麼選擇 Cloudinary?
考慮過幾個方案:
- 靜態預設圖片:太單調,失去個性化
- 手動設計封面:每篇文章都要設計,不切實際
- 自架 Vercel Edge Function:需要額外專案,維護成本高
- Cloudinary:免費額度足夠,內建文字覆蓋 API,支援自訂字型 ✅
實作步驟
1. 註冊 Cloudinary 並上傳背景圖片
首先註冊免費帳號,記下你的 Cloud Name(我的是 dynj7181i)。
然後建立一張 1200×630px 的背景圖片。我選擇使用 SVG 製作漸層背景:
<svg width="1200" height="630" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#556bff;stop-opacity:1" />
<stop offset="100%" style="stop-color:#3644d8;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="1200" height="630" fill="url(#grad)" />
<text x="1140" y="600" font-family="Arial" font-size="24"
fill="#ffffff" opacity="0.8" text-anchor="end">(b)-log</text>
</svg>
上傳後得到 Public ID:og-background_cbst7j
2. 上傳 Noto Sans TC 字型
這是關鍵步驟。Cloudinary 的內建字型(如 WenQuanYi Zen Hei)雖然支援中文,但視覺效果不夠現代。我想用 Noto Sans TC。
重要:字型必須作為 authenticated raw file 上傳,且 Public ID 不能包含底線。
步驟:
- 前往 Cloudinary Settings → Upload Presets
- 建立新 preset:
- Signing Mode:Signed
- Delivery type:Authenticated
- 使用此 preset 上傳
NotoSansTC-Bold.ttf - 設定 Public ID 為
notosanstc-bold.ttf(全小寫,無底線)
3. 測試文字覆蓋 API
Cloudinary 的文字覆蓋語法是這樣的:
https://res.cloudinary.com/{cloud_name}/image/upload/
c_fill,w_1200,h_630/
co_rgb:ffffff,
l_text:{font_id}_{size}_{alignment}:{encoded_text},w_{max_width},c_fit/
fl_layer_apply,g_center/
{background_id}.png
關鍵參數:
co_rgb:ffffff:文字顏色(白色)l_text:notosanstc-bold.ttf_60_center:...:使用自訂字型,60px,置中對齊w_1000,c_fit:限制文字寬度 1000px,自動縮放和換行fl_layer_apply,g_center:套用文字圖層並置中
測試時發現:
- 60px 字型 + 1000px 寬度:完美,無白邊
- 60px 字型 + 1100px 寬度:長標題會超出邊界
- 50px 字型:文字太小,視覺效果不佳
4. 修改 generate-redirects.js
在生成 WordPress 風格頁面時,預先填入 Cloudinary URL:
// 生成 Open Graph 圖片 URL
let ogImageUrl;
if (coverImage) {
ogImageUrl = `${baseUrl}/${coverImage}`;
} else {
const cloudName = 'dynj7181i';
const backgroundId = 'og-background_cbst7j';
const fontId = 'notosanstc-bold.ttf';
const encodedTitle = encodeURIComponent(title);
ogImageUrl = `https://res.cloudinary.com/${cloudName}/image/upload/` +
`c_fill,w_1200,h_630/` +
`co_rgb:ffffff,` +
`l_text:${fontId}_60_center:${encodedTitle},w_1000,c_fit/` +
`fl_layer_apply,g_center/` +
`${backgroundId}.png`;
}
這樣每篇文章都會自動生成包含正確 OG 圖片 URL 的頁面。
遇到的坑
坑 1:字型檔案上傳失敗(Error 400)
一開始直接在 Media Library 上傳字型,Cloudinary 自動加上底線後綴(如 NotoSansTC-Bold_i1elwz.ttf),導致文字覆蓋 API 無法識別。
解決方法:必須使用 authenticated upload preset,並手動設定不含底線的 Public ID。
坑 2:長標題超出圖片邊界
測試「OpenAI的矛盾:一邊降溫一邊加熱的危險遊戲」這樣的長標題時,發現文字超出 1200px 寬度,導致左右出現白邊。
解決方法:加入 w_1000,c_fit 參數,限制文字區域寬度並自動縮放。
坑 3:Facebook 快取問題
即使 OG 圖片 URL 正確,Facebook 可能還是顯示舊的預覽。
解決方法:使用 Facebook Sharing Debugger 強制重新抓取:
- 輸入文章 URL
- 點選「Scrape Again」
- 確認預覽正確
最終效果
現在所有文章的 Facebook 分享預覽都能正確顯示:
- ✅ 標題使用 Noto Sans TC Bold 字型
- ✅ 白色文字於藍色漸層背景
- ✅ 自動換行,無白邊
- ✅ 右下角有 (b)-log 浮水印
最重要的是:完全自動化。未來新增文章時,GitHub Actions 會自動生成包含正確 OG 圖片的頁面,無需手動操作。
技術細節總結
Cloudinary 設定:
- Cloud Name:
dynj7181i - 背景圖片:
og-background_cbst7j(1200×630px SVG 漸層) - 字型:
notosanstc-bold.ttf(authenticated raw file)
最佳配置:
- 字型大小: 60px
- 文字寬度限制: 1000px
- 對齊方式: center
- 自動縮放: c_fit
成本:
- Cloudinary 免費額度:每月 25 credits
- 每次圖片生成約消耗 0.0001 credits
- 可支援約 250,000 次預覽請求/月(遠超實際需求)
學到的教訓
不要假設第三方服務支援所有語言 英文能用不代表中文也能用。測試時要用實際內容,不要只用「test」。
了解平台限制很重要 Facebook 不執行 JavaScript,這個基本認知能省下很多偵錯時間。
自動化是值得投資的 花幾小時設定好自動化流程,未來能省下無數次重複操作。
免費服務也能很強大 Cloudinary 的免費額度對個人部落格來說綽綽有餘,不一定要自己架設服務。
下一步
目前所有文章都使用統一的漸層背景。未來可以考慮:
- 為重要文章設計專屬
coverImage - 根據文章分類使用不同背景顏色
- 加入更多視覺元素(圖示、裝飾線條等)
但現在這樣已經很好了。能用、好看、自動化,這就是我要的。
相關資源: