分享卡片只有一个任务:当某人滚动信息流时,能在大约一秒钟内明白该产品的用途。有效的卡片会展示产品的实际运作,例如一份已签署的提案、一个可由客户确认的提醒、或一个报价金额,而不是一个浮在渐变背景上的 logo。通过代码生成卡片,使其与品牌保持同步,并允许之后无需设计工具即可修改。
1. 编写代码前收集品牌信息
按以下顺序阅读现有内容:设计文档(DESIGN.md、PRODUCT.md、样式指南)、CSS 令牌(globals.css、Tailwind 的 @theme、CSS 自定义属性)、落地页的标题和副标题,以及 logo(SVG 组件或文件)。使用实际的十六进制值以及实际的显示字体和正文字体。使用与网站不同的字体的卡片会显得与品牌不符。
查找现有的设置(opengraph-image.*、og.png.*、布局中的 og:image)并进行扩展,而不是添加第二个。
然后决定卡片上应显示什么 mock。询问用户使用产品后客户手中会有什么(发票、确认邮件、仪表盘图块、收据)并绘制出来。如果不太明显,请用一句话提出一个建议,并在用户反对之前继续执行。
2. 构建卡片
除非用户或现有卡片另有说明,请从以下布局开始。该布局在信息流以小尺寸显示时效果良好。
| 区域 | 内容 |
|---|---|
| 画布 | 1200x630。品牌背景,纯色或朝向 mock 的柔和径向渐变。 |
左栏,宽约 620 到 660 像素,内边距约为 60px 0 60px 72px,使用 justify-content: space-between 分隔 | 顶部:logo 标记加文字标记,字号 34 到 38 像素。中间:标题,字号 64 到 76 像素,行高紧凑(0.98 到 1.08),字符间距略为负值。底部:一条柔和的副标题,字号 26 到 28 像素。 |
| 右侧 | 使用品牌颜色和真实数据的产品 mock。将其倾斜 2 到 4 度,在其后方放置一张朝相反方向倾斜的强调色背景卡片,并添加柔和阴影,例如 0 24px 48px -20px rgba(0,0,0,0.35)。 |
有助于提升效果的小细节:在 mock 上添加印章或徽章(“已付款”、“已确认”),在 mock 的角上叠加一张带有关键数字的纸条,以及低透明度的淡色背景线条。
文案:
- 标题是产品的承诺,最好与落地页引导语相同。具体胜过巧妙。
- Mock 数据应具体且可信(
$1,510.00、38 张卡片、一个合理的客户姓名)。使用 Lorem Ipsum 占位文本或$XX会使产品看起来未完成。 - 用强调色突出标题中的某个短语可能会有所帮助。超过一个会削弱效果。
- 保持文字尺寸较大。信息流通常以卡片三分之一的大小显示,因此任何小于 18 像素的内容都会消失。
3. 渲染
使用 Satori,它将类似 JSX 的树转换为 SVG,然后光栅化为 PNG。Next.js 将其作为 next/og 内置提供。在其他情况下,将 satori 与 @resvg/resvg-js 配对使用。针对不同框架的配置(Next.js App Router、Astro 以及其他静态站点的纯构建脚本),请阅读 references/frameworks.md。
Satori 仅支持 CSS 的子集,这些限制是大多数失败的原因:
- 字体必须是真实的 TTF、OTF 或 WOFF 文件,并在渲染时传入。WOFF2 不起作用,也没有系统字体回退。只加载你使用的两到三种字重。references/frameworks.md 介绍了如何获取字体文件。
- 任何包含多个子元素的元素都需要
display: "flex"。否则 Satori 会抛出错误,因此默认每个盒子都设为 flex。 - 没有 CSS 网格、没有 CSS 变量、没有
calc()。将字面颜色放在文件顶部的一个小映射中(const C = { ink: "#1c2128", ... })。 - 文本会自动换行。注意在最后一行单独出现的单词以及文本与 mock 重叠的情况。通过显式分割行(一系列 span)或调整宽度和大小来解决。
whiteSpace: "nowrap"加上flexShrink: 0可使价格和行项目保持在一行内。 position: "absolute"在相对定位的 flex 父元素内有效。将其用于背景卡片、印章和纸条。- 内联 SVG 路径渲染效果良好,因此重用 logo 的 SVG 路径而不是嵌入其图像。本地光栅图像以 base64 数据 URI 的形式嵌入。
4. 替代文本和标签
编写 og:image:alt,描述图像实际显示的内容,格式为“品牌:mock 显示的内容,以及标题。”例如:“Acme Invoices:一张金额为 $1,510.00 且带有“已付款”印章的发票,旁边是标题:在离开工地之前拿到钱。”
页面需要包含以下绝对 URL 的标签:og:title、og:description、og:image、og:image:width(1200)、og:image:height(630)、og:image:alt、将 twitter:card 设置为 summary_large_image,以及 twitter:image。相对的 og:image 是卡片不显示的最常见原因,因为大多数 unfurler 不会解析它。
5. 通过查看进行验证
在确认 PNG 之前,不要认为卡片已完成。
-
启动开发服务器,获取图像,并在图像查看器中打开它,或者使用你的文件读取工具(如果它能显示图像)。
-
仔细检查:孤立的单词、与 mock 重叠的文本、在画布边缘被裁剪的阴影、不均匀的内边距、回退字体(看起来明显不对)以及低对比度的副标题。修复它们并重新渲染,直到看起来干净为止。
-
同时检查标签和图像:
python3 scripts/check_og.py http://localhost:3000/ --out /tmp/og-check.png它会列出所有 OG 和 Twitter 标签,获取图像,确认其尺寸为 1200x630 且小于 5MB,标记相对 URL 和错误的卡片类型,并在遇到任何问题时以退出码 1 退出。打开保存的 PNG 以确认它是你期望的图像。
-
运行生产构建以确保图像仍然能正常生成。
-
部署后,针对线上 URL 运行检查器。告知用户 Slack、LinkedIn 和其他平台会缓存 unfurl 结果,因此在更改之前分享的链接可能会在短时间内继续显示旧卡片。LinkedIn 的 Post Inspector 可以强制刷新。
完成后,向用户提供 PNG 的路径以及一个简短的段落,描述布局和 mock 显示的内容。