工具、资源与工作台 ·
我为什么又造了一个公众号排版工具
文章内容写完,只能算完成了一半。剩下一半,是怎么让它在手机上看起来像个人写的,而不是从某个后台系统里直接倒出来的说明书。
[toc]
对于写公众号来说,排版这事儿真的挺折磨人的。
文章内容写完,只能算完成了一半。剩下一半,是怎么让它在手机上看起来像个人写的,而不是从某个后台系统里直接倒出来的说明书。
这事我之前也没少折腾。
一开始用过 mdnice。优点很明显,模板多,一键渲染,初始体验确实不错。你把 Markdown 往里一贴,右边效果就出来了,刚开始会有一种“还可以”的感觉。
但用久了以后,问题也出来了。
模板风格比较固定,想细调就不太顺手;每次渲染也容易变慢;更重要的是,预览的时候是一回事,复制到公众号里又是另一回事。
后来又用过 md.gzcx.net。这个工具的好处是可以自定义 CSS,短期内挺爽。你想调字号、调间距、调标题样式,都能自己写。
但问题是,长期维护一套公众号 CSS,真不是啥轻松活。
今天调一下引用块,明天表格又不舒服;这篇文章代码块多,那篇文章图片多;再加上微信公众号编辑器自己还会过滤一部分样式,最后就变成了:我明明是在写文章,结果每天都像是在调兼容性 bug。
这您受得了吗。
所以针对这两个工具的痛点,下决心写了一个我自己的排版工具 --- Layweout。
项目地址:https://github.com/crisxuan/layweout
线上地址:https://layweout.vercel.app
Layweout 是什么
Layweout 这个名字来自 layout + we。
layout 是布局排版,we 是微信公众号,合起来就是一个专门给公众号场景做排版输出的工具。
这个名字我自觉有点小聪明,但还算逻辑自洽。
它不是一个单纯的 Markdown 渲染器,也不是一个模板展示器,而是一个面向公众号发布流程的本地工作台。
现在的工作流大概是这样:
左侧是样式区,选择文章模板。
中间是文本区,可以输入 Markdown、HTML,也可以直接粘贴富文本。
右侧是手机端阅读预览,用来快速判断排版节奏。
最后点击复制,工具会重新生成一份适合公众号编辑器粘贴的内联样式 HTML。
这里有个很关键的点:
Layweout 不直接复制预览 DOM。
因为浏览器预览和公众号编辑器根本不是一个环境。
浏览器里能跑的 CSS,公众号编辑器不一定认。你在本地看着背景、渐变、圆角、边距都挺好,粘进去以后可能直接没了。
所以 Layweout 的核心逻辑不是“把右边预览复制过去”,而是:
输入内容
↓
统一清洗和渲染
↓
浏览器预览
↓
重新生成公众号兼容 HTML
↓
复制到公众号编辑器
说白了,预览是给人看的,导出是给公众号编辑器看的。
这俩不能混在一起。
为什么我不满足于现成工具
mdnice 这类工具当然不是不好。
它适合快速排版,适合不想折腾的人。模板一选,文章一贴,基本就能出稿。
但我的问题是,我写的东西经常比较长,而且内容类型不固定。
有时候是 AI 工具体验,有时候是技术踩坑,有时候是产品思考。里面可能有代码块、表格、引用、截图、列表、分割线。
这时候模板如果只是“看起来漂亮”,是不够的。
它必须得扛得住真实内容。
我对排版工具的要求其实就三条:
第一,正文要舒服。
公众号大部分阅读都发生在手机上,正文的字号、行高、段间距,比花哨的标题重要多了。
第二,复杂元素不能炸。
代码块、表格、引用块、图片说明,这些东西一旦出问题,整篇文章立刻显得很业余。
第三,复制到公众号以后不能大变样。
预览再好看,粘进去崩了,那都是白搭。
现成工具最大的问题,就是第三点。
它们通常更重视预览效果,但对“公众号编辑器到底认不认这份 HTML”这件事,处理得不够彻底。
而 Layweout 反过来想。
先保证粘进去稳,再谈样式好不好看。
这个顺序很重要。
前端架构怎么设计
Layweout 现在的架构不复杂,但边界比较清楚。
大体分成几层:
core 负责输入内容清洗和转换
data 负责模板数据、分组和 schema
ui 负责页面结构
styles 负责工作台 UI 和浏览器预览样式
export 负责公众号兼容 HTML 输出
utils 负责剪贴板、统计等辅助能力
这个分层的目的不是为了显得多高级。
而是为了避免以后每改一个模板,都要全项目到处找地方。
我最烦这种代码:
今天新增一个模板,要改数据。
还要改 UI。
还要改 CSS。
还要改导出逻辑。
还要改复制逻辑。
最后还不知道有没有把其他模板弄坏。
这种东西一开始写起来快,但后面维护起来很痛苦。
所以 Layweout 里把几个变化点拆开了。
输入层:先把内容收敛起来
用户输入可能来自三种地方:
MarkdownHTML- 富文本
这三种东西表面上都是文章,但结构完全不一样。
Markdown 要先通过 marked 转成 HTML。
HTML 和富文本要经过 DOMPurify 清洗,去掉危险或无意义的属性。
然后工具还会做一些规范化处理,比如把 b 转成 strong,把 i 转成 em,把散落的文本节点包成段落。
这个步骤看起来很基础,但特别重要。
输入不收敛,后面所有模板都是在赌。
你不能指望一堆来源不一致的 DOM,直接套样式还能稳定。
所以 Layweout 的第一步不是变漂亮,而是先把内容变干净。
模板层:模板不是一堆 CSS
Layweout 现在内置了 22 套带独立导出 profile 的模板,按出版、科技、品牌生活分组。
这 22 套模板不是简单换颜色。
每套模板都有自己的 tokens,比如:
- 页面背景
- 正文颜色
- 强调色
- 引用块背景
- 代码块颜色
- 表格样式
- 字体
- 行高
- 间距
- 外层容器背景
这些东西集中放在模板 registry 里。
大概是这个思路:
presets/
groups.js 模板分组和治理状态
registry.js 模板 token
schema.js 模板校验和可见模板派生
这个设计解决了一个很实际的问题:
模板多了以后,需要治理。
不是所有模板都应该暴露给用户。
早期的一些模板可能能用,但没有独立导出 profile,也不够稳定。那就先隐藏,而不是硬塞到选择器里凑数量。
模板库不是越多越好。
打开以后每一个都能用,才是真的好。
预览层:让人判断阅读节奏
预览层负责浏览器里的展示效果。
这里可以用 CSS 文件,可以用 CSS 变量,可以做更舒服的手机阅读模拟。
Layweout 的预览不是为了 100% 复刻公众号编辑器,因为这个事情本身就不现实。
公众号编辑器会过滤样式,不同内容粘贴进去也可能有差异。
所以预览层的目标是:
尽量模拟公众号手机端阅读效果,让作者快速判断文章节奏。
标题是不是太重。
正文是不是太挤。
引用块是不是抢戏。
代码块是不是可读。
表格有没有溢出。
这些问题,在预览区就应该能看出来。
但最终复制效果,还是以导出模块重新生成的 HTML 为准。
这也是 Layweout 和很多排版工具不一样的地方。
它没有把预览当最终结果。
它把预览当一个中间环节。
导出层:真正的重点在这里
Layweout 最核心的地方,其实是 src/export/wechat.js。
这个模块会重新生成一份公众号兼容 HTML。
流程大概是这样:
拿到渲染后的 HTML
↓
根据当前模板 profile 生成内联 style
↓
处理链接、列表、引用块等结构
↓
补充 background-color 兜底
↓
对背景和引用块做公众号兼容处理
↓
返回可以复制的 HTML
为什么一定要内联样式?
因为公众号编辑器不会完整保留外部 CSS。
你用 class 写得再优雅,复制进去以后可能什么都没了。
所以导出时要把关键样式写到元素的 style 属性里。
这听起来不优雅。
但公众号排版不是前端架构审美大赛。
能稳定粘贴,才是第一目标。
Layweout 还做了几个兼容策略。
第一,复杂背景会补 background-color。
因为渐变和复杂背景可能丢,但纯色背景相对更稳。
第二,带背景的模板会做外层包裹。
这样可以尽量避免粘贴后块与块之间出现白缝。
第三,引用块会做额外处理。
有些引用块用普通 blockquote 在公众号里不稳,所以会转成更保守的表格结构。
这听着有点老派。
但没办法,公众号编辑器就吃这一套。
为什么不把标准模式暴露给用户
之前工具里做过“标准模式 / 兼容模式”。
标准模式输出更轻,兼容模式输出更稳。
听起来挺合理。
但后来我想明白了,这个按钮不应该给用户看。
因为用户来用 Layweout,不是为了研究 HTML 输出策略的。
他只想知道:我复制到公众号里,会不会变形。
那默认就应该给最稳的兼容导出。
所谓标准模式,保留在内部测试里就行了。比如做快照对比、排查导出结构变化时有用。
但放在界面上,只会制造选择负担。
很多产品的问题,不是功能不够,而是把本该系统承担的复杂性,甩给了用户。
这事我现在特别警惕。
用户不应该理解你的兼容策略。用户只应该得到一个稳定结果。
快照测试:防止改一个模板,炸一片模板
做模板工具,还有一个很容易忽略的问题:回归测试。
22 套模板,看起来不算特别多,但如果每次都手动测试,根本不现实。
你改了一个 blockquote 的导出逻辑,可能影响所有模板。
你改了背景兼容策略,可能让某几个模板出现断层。
你改了列表标记,可能把有序列表和无序列表一起弄乱。
所以 Layweout 加了导出快照测试。
测试会拿一份覆盖比较全的文章样例,里面有标题、正文、链接、引用、列表、代码块、表格、图片,然后对所有可见模板生成导出 HTML 快照。
以后改导出逻辑,只要跑:
npm run test:snapshots
如果快照变了,就说明输出确实发生变化。
这时候再判断,是预期修改,还是误伤。
这个东西没有什么视觉冲击力,但很实用。
因为排版工具最怕的不是今天有 bug。
最怕的是你今天修了一个模板,顺手把其他 21 个模板打坏了。
Layweout 的优势到底在哪
总结一下,Layweout 的优势不是“模板更多”。
其实 22 套模板也不算特别夸张。
它真正的优势在四个地方。
第一,本地工作台。
不用每次依赖一个在线编辑器状态,打开就能写,输入、预览、复制都在一个地方完成。
第二,输入来源更宽。
Markdown、HTML、富文本都能进来,而不是强迫你必须用某一种写作方式。
第三,预览和导出分离。
浏览器预览负责看效果,公众号导出负责兼容性。这两个边界一拆开,问题就清楚很多。
第四,模板有治理。
模板不是随便堆 CSS,而是有 token、有 profile、有分组、有 schema、有快照测试。
这些东西放在一起,最后带来的体验是:
你可以更放心地写长文。
不用每次都担心复制以后排版变形。
不用每篇文章都手调 CSS。
不用把注意力浪费在“这个引用块为什么又没背景了”这种问题上。
其他排版工具的问题,不是不好,而是不适合我的长期场景
这里还是要说一句,mdnice 和 md.gzcx.net 这类工具并不是没价值。
它们解决的是快速排版问题。
如果只是偶尔发文,或者对模板细节要求不高,这些工具完全够用。
但我的场景不是这样。
我需要长期写。
需要反复改。
需要不同类型文章都能保持稳定。
需要代码、表格、引用、图片这些复杂内容都能扛住。
这时候,传统排版工具的问题就会变明显:
预览和复制结果不一致。
模板看着多,但风格很固定。
自定义 CSS 前期爽,后期维护累。
复杂背景和布局进公众号以后容易丢。
文章越长,手动修补成本越高。
所以我不是想做一个“更花哨的 mdnice”。
我想做的是一个更可控的公众号发布工作台。
最后
排版这事,说小也小。
它不像模型能力,不像产品架构,不像数据库性能,看起来没那么硬核。
但对内容创作者来说,它非常现实。
一篇文章写得再认真,如果排版乱七八糟,读者的阅读成本会立刻升高。
尤其公众号这种场景,大部分人都在手机上看。
屏幕就那么大。
正文挤一点,标题重一点,引用块乱一点,读者可能就划走了。
所以我现在越来越觉得:
排版不是装饰,排版是内容的交付方式。
Layweout 做的事情,本质上就是把这条交付链路变稳定。
从输入,到预览,到模板,到复制,到公众号编辑器,每一步都尽量收敛。
不追求花哨。
先追求稳定。
稳定之后,再追求好看。
这也是我现在做工具越来越明确的一个判断:
好工具不是把所有选项都摊开给用户,而是把复杂性消化掉,然后给用户一条最顺的路。
Layweout 现在还不算完美。
但至少它已经解决了我最头疼的问题:
文章写完以后,我不用再和公众号编辑器斗智斗勇了。
这就已经很值了。