1200×630像素,这是Open Graph协议规定的社交分享图尺寸。但当你把精心设计的模板搬进Next.js的next/og时,可能会发现——一半元素凭空消失了。没有报错,没有警告,Satori渲染引擎只是默默忽略了它不支持的CSS特性。
本文作者踩过这个坑:Grid布局被吞,calc()计算失效,CSS变量变成"未知值"。更糟的是,降级渲染让问题直到Slack分享时才暴露。他的替代方案是——用真实浏览器渲染HTML,截图生成PNG。同样的开发体验,无需记忆CSS子集。
![]()
一、Satori的"聪明"与代价
Satori是Vercel @vercel/og背后的渲染引擎。它的工作流很精巧:解析JSX,近似模拟CSS子集,生成SVG再栅格化为PNG。对于简单卡片——标题加纯色背景、单一字体——确实够用。
但设计师给的往往是正经营销物料。作者列出的限制清单很具体:
Flexbox支持,Grid不支持。display: flex必须在每个容器显式声明,包括,因为Satori的默认值与浏览器不同。自定义字体要在请求处理函数内获取并传入ImageResponse,不能在模块作用域加载。整个打包体积(含字体和内联图片)在Edge环境下须低于500KB。CSS变量不解析,calc()不计算。阴影"基本能用",直到不能用。
这些限制可以逐个绕过。作者确实绕了一段时间。但核心痛点是:每次设计调整都变成翻译工作——你不是在写CSS,而是在写"Satori能懂的CSS子集"。反馈循环还很慢,因为渲染发生在Edge的请求时。
二、真实浏览器方案的吸引力
作者反复回归的替代方案:在真实Chromium实例中渲染模板。写正常的HTML和CSS,包括Grid、变量、@font-face加载的自定义字体、甚至可以冻结在特定帧的动画。然后截图1200×630,输出PNG。
唯一的问题是Chromium跑在哪。
自己在Vercel或AWS Lambda上跑Puppeteer可行,但繁琐。Chromium二进制文件超出默认Lambda体积限制,得用@sparticuz/chromium或Layer,盯着内存用量,处理冷启动,Chrome更新搞崩东西时还要固定版本。对于一个"每次有人分享链接都必须可靠工作"的OG图片管道,作者不想拥有这个问题。
他的选择是:调用一个"收HTML、返PNG"的API。整个基础设施类别被砍掉。
三、为什么这件事值得技术人关注
这个案例的深层价值在于:它揭示了"开发者体验"与"运行时约束"之间的经典张力。Vercel的方案把渲染推到Edge,换取低延迟,但牺牲了CSS完整性和调试友好性。浏览器方案把渲染集中到托管服务,用网络延迟换开发效率和视觉保真度。
作者没有给出具体API推荐,但逻辑很清晰:当基础设施的复杂度超过业务价值时,外包给专门做这件事的服务是理性选择。OG图片不是核心竞争力,可靠生成才是。
对于25-40岁的技术从业者,这个决策框架比具体代码更有迁移价值:评估一个技术方案时,把"我是否想拥有这个问题"作为关键过滤器。Satori的500KB限制、冷启动、版本锁定——这些都是"问题所有权"的隐性成本。作者的选择是明确拒绝。
如果你正在Next.js里折腾动态分享图,先问自己:模板复杂度会长期增长吗?团队有前端设计师吗?答案是的话,趁早评估浏览器渲染方案。省下的翻译工作和调试时间,够你写好几个功能了。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.