链接发到微信、推特、Slack——会显示一张卡片预览,里面有标题、描述、缩略图。这背后是 Open Graph Protocol(OGP),但每个平台的解析规则不同,缓存策略不同,对图片尺寸的容忍度不同。
OG 协议核心字段
| 字段 | 含义 | 是否必填 |
|---|---|---|
og:title | 标题(可与 <title> 不同) | ✅ |
og:description | 一句话描述 | ✅ |
og:image | 卡片图片绝对 URL | ✅ |
og:url | 规范 URL(避免 UTM 参数干扰) | ✅ |
og:type | website / article / product / video… | 推荐 |
og:site_name | 站点名 | 推荐 |
og:locale | zh_CN / en_US | 推荐 |
og:image:width / og:image:height | 图片尺寸(帮助预渲染布局) | 推荐 |
Twitter Card 补充字段
| 字段 | 含义 |
|---|---|
twitter:card | summary / summary_large_image / app / player |
twitter:title | 标题(覆盖 og:title) |
twitter:description | 描述(覆盖 og:description) |
twitter:image | 图片(覆盖 og:image) |
twitter:site | @站点账号 |
twitter:creator | @作者账号 |
关键差别:og: 用 property=,twitter: 用 name=——写反了部分解析器会忽略。
1200×630 由来
Facebook 早期定义卡片为 1.91:1
1.91:1 + 1200px 宽 → 1200×629.3 ≈ 1200×630
Retina 2x 时缩放到 600×315 显示,仍清晰
最低尺寸 600×315,否则 Facebook 拒绝。
各平台显示规则(速查)
| 平台 | 优先级 | 缓存 | 图片裁剪 | 备注 |
|---|---|---|---|---|
| og: > 任何 | 30 天 | 1.91:1 完整显示 | Sharing Debugger 强制刷新 | |
| Twitter / X | twitter: > og: | 7 天 | summary_large_image 完整显示 | 改 URL 参数刷新 |
| og: only | 7 天 | 1.91:1 完整显示 | Post Inspector 刷新 | |
| Slack | og: only | 24 小时 | 完整显示 | 不识别 og:image:secure_url |
| Discord | og: only | ≈1 小时 | 完整显示 | 不支持 SVG |
| 微信 PC | og: + 自有解析 | 不公开 | 完整显示 | 移动端规则不一致 |
| iMessage | og: only | 较长 | 1.91:1 + 圆角 | 物理显示宽 ≈280px |
| og: only | 较长 | 完整显示 | 强烈依赖 og:image |
安全区设计
┌──────────── 1200 ────────────┐
│ 安全边距 100px │ 60
│ ┌────────────────────────┐ │
│ │ │ │
│ │ 主标题文字 │ │ 630
│ │ 1000×450 内 │ │
│ │ │ │
│ └────────────────────────┘ │
│ │ 60
└──────────────────────────────┘
- 主标题:60-100px 字号
- 描述:30-50px
- 装饰边距:≥60px
调试工具速链
| 平台 | 工具 |
|---|---|
| https://developers.facebook.com/tools/debug/ | |
| https://www.linkedin.com/post-inspector/ | |
| 通用预览 | https://opengraph.dev/ |
| Slack | 在 Slack 输入 URL 重抓 |
curl 模拟抓取:
curl -A "facebookexternalhit/1.1" -L https://你的页面 | grep -i og:
常见错误清单
- ❌ og:image 用相对路径或
//协议无关——抓取器读不到 - ❌ og:image 用 HTTP 不是 HTTPS——iOS / 微信拒绝
- ❌ JS 注入 og meta——抓取器不执行 JS,SSR / 预渲染才行
- ❌ 图片在 robots.txt 禁止——抓取被 403
- ❌ 改了图但平台还显示旧的——平台有缓存,要么强刷要么换 URL
- ❌ 图上文字太小——预览缩略图尺寸下文字糊掉
- ❌ og:title 和
<title>重复——浪费描述空间,应该写更营销化的标题 - ❌ Twitter 用了
summary但图是 1.91:1——会被压缩成正方形
自动化生成方案
| 方案 | 工具 | 适用 |
|---|---|---|
| 构建时生成 | @vercel/og + Astro Endpoint | 静态站,页面数 < 1000 |
| 构建时生成 | satori + puppeteer | 同上,复杂模板 |
| 边缘函数 | Cloudflare Workers / Vercel OG | 动态参数化 |
| 模板手画 | Figma / Canva 导出 | 少量重要页面 |
Astro 推荐:astro-og-canvas 或 astro-og-image-generator,构建时为每篇 markdown 生成对应 OG 图。
实操流程
- 设计 1200×630 模板,标题占位字号定下
- 各页面 frontmatter 配
title/description - 构建时为每篇文章生成 OG 图到
/og/<slug>.png - 模板里输出 og: 和 twitter: 系列 meta
- 用 Facebook Sharing Debugger 抓一次新页面,确认图能加载
- 链接发到自己微信 / Slack 测试,看预览是否符合预期
- 更新图后用 URL 参数(
?v=2)强制各平台重抓
OG 图是站外曝光的”封面”——优化它的成本远低于优化首屏内容,但点击率提升经常立竿见影。