微信公众号排版踩坑:列表里的行内代码后面,文字总是莫名换行

记录一下通过 API 给微信公众号发草稿时,列表项里的行内代码后面的文字总被挤到下一行。本文记录完整排查过程与实测结论:微信编辑器会把行内 code 块级化、会剥掉无属性的 span、会把以元素开头的 li 里的裸文本包成块级 section。最终修法是把行内代码转成带 style 的 span,并给 li 内裸文本预先包上带 style 属性的 span。

阅读时长: 3 分钟
共 1328字
作者: eimoon.com

我的公众号文章是用脚本从博客 Markdown 转成内联样式的 HTML,再走 draft/add 接口发到草稿箱的。最近发现一个顽固的排版 bug:列表项里只要出现行内代码,它后面的说明文字就会被挤到下一行

预期是一行:

- low:简短、对延迟敏感的任务

实际渲染出来变成两行:

- low:
  简短、对延迟敏感的任务

发出去的 HTML 明明没问题,浏览器里渲染也正常,唯独微信编辑器和手机端阅读时断行。折腾了好几轮才定位到根因,记录一下。

排查过程:四个都不对的猜测

猜测一:<code> 标签的锅。 微信编辑器确实会把行内 <code> 块级化(甚至会把后面的文字吞进 code 元素里),于是把行内代码全部转成带样式的 <span>。HTML 干净了,但还是断行。

猜测二:等宽字体触发的。 怀疑编辑器靠 font-family: monospace 识别"这是代码"然后特殊处理。去掉等宽字体,还是断行。

猜测三:行内元素类型的问题。 把 span 降级成 <strong style="color: ..."> 纯加粗变色,还是断行——说明跟用什么行内元素根本没关系。

猜测四:把 li 里的裸文本包进 <span> 就好了。 这一步方向对了,但包了个无属性的空 span,依然断行。原因后面揭晓。

到这里有个关键的调试技巧:draft/get 接口把存进草稿箱的 HTML 拉回来对比。结果发现 API 存储的内容和我发的一模一样——问题不在传输,而在微信编辑器打开草稿时会对 HTML 做一轮"规范化"重写。拉取一篇被编辑器保存过的旧草稿,看到了真凶:裸文本被包成了块级的 <section>

一次测试定位根因

与其继续猜一轮发一轮,不如把所有假设塞进一篇测试草稿里一次验证。发了 6 个变体的 li:

  • A:li 以裸文本开头,后面跟行内元素
  • B:li 以行内元素开头,后面的裸文本包无属性 <span>
  • C:li 以行内元素开头,后面的裸文本包带 style<span>
  • D:整个 li 内容包一层带 style 的 span
  • E:行内元素用 <strong> + 带 style 的 span 包裸文本
  • F:纯裸文本对照组

手机上一看,结果非常清晰:只有 B 断行,其余全部正常。

根因:三条实测验证的编辑器行为

  1. li 以行内元素开头时,编辑器会把后续的裸文本节点包成块级 <section>——这就是断行的直接原因。li 以裸文本开头则完全安全。
  2. 无属性的 <span> 会被编辑器直接剥掉,文字重新变回裸文本,等于没包。这就是猜测四失败的原因。
  3. 带 style 属性的 <span> 会被保留,里面的文字不会被 section 化。

所以修法很简单:转换脚本里把 li 下的裸文本节点预先包进带 style 的 span。用 BeautifulSoup 写出来就几行:

for li in soup.find_all('li'):
    for child in list(li.children):
        if isinstance(child, NavigableString) and child.strip():
            wrapper = soup.new_tag('span')
            # style 属性不能少,无属性的 span 会被编辑器剥掉
            wrapper['style'] = 'display: inline'
            child.wrap(wrapper)

配合行内 <code> → 带样式 <span> 的转换,列表里的行内代码终于稳定不断行了。

顺带的两个经验

调试方法比修复本身更值得记。 公众号排版问题的难点是反馈链路长:改脚本 → 发草稿 → 手机看效果。两个提效手段:

  • draft/get 拉回存储的 HTML,区分"我发的就是坏的"还是"微信改写了它"
  • 把多个假设做成 A/B/C…变体塞进一篇测试草稿,一次往返验证全部猜想

注意 2 万字符上限是含 HTML 标签的。 每个标签都带内联样式时,3500 字左右的 Markdown 就能撞上 draft/add 的限制。省字符的思路:可继承属性(字体、行高、颜色)只写在最外层包裹 div 上,高频标签只留必要属性。我的文章用精简主题后 HTML 从 21769 字符降到 14256,足够塞下 6000 字正文。

关于

关注我获取更多资讯

月球基地博客公众号二维码,扫码关注获取更多 AI 与编程资讯
📢 公众号
月球基地博客作者个人微信二维码,扫码交流 AI 与编程话题
💬 个人号
使用 Hugo 构建
主题 StackJimmy 设计