文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
浏览器解析html时会自动修正非法嵌套,如xxx被改为xxx,因只允许“短语内容”子元素,属流内容故被移出;css和js操作均基于修正后的dom。

为什么浏览器会“擅自修改”你写的 <p></p>
<div>xxx</div>
不是浏览器“bug”,是 HTML 解析器严格按规范执行:只要遇到 <div> 这类块级元素,它会立刻闭合当前 <code><p></p>,再把 <div> 插到外面。结果 DOM 变成 <code><p></p>
<div>xxx</div>
<p></p> —— 原来的 <p></p> 被拆成两个空标签。
这种修正发生在 HTML 解析阶段,CSS 还没开始计算,display: inline 完全无效。你看到的源码结构 ≠ 实际 DOM 结构。
常见连锁反应包括:
-
document.querySelector('p > div')永远返回null -
p > div这类 CSS 选择器完全不匹配 -
<p></p>上设的padding、margin对<div> 无影响(因为 <code><div> 已不在其内部) <li>W3C 验证器明确报错:<code>Element div not allowed as child of element p - 文本节点(直接写的文字)
-
<strong></strong>、<em></em>、<small></small>、<mark></mark> -
<a></a>(注意:它可含块级,但这是特例)、<img>、<time></time>、<code> -
<button></button>、<input>、<select></select>(属于“可替换行内元素”,部分浏览器允许,但跨平台稳定性差)
<p></p> 允许嵌套哪些元素?只看“短语内容”定义
HTML Living Standard 明确规定 <p></p> 的内容模型是 “phrasing content”(短语内容),不是“看起来像行内”的元素,而是规范里白纸黑字列出的那些。
合法子元素包括:
非法的不只是 <div>,还有:<code><h2></h2>~<h6></h6>、<ul></ul>、<ol></ol>、<table>、<code><form></form>、<blockquote></blockquote>、<section></section> 等所有 flow content 元素。
JS 动态插入时同样受限制:innerHTML = '<p></p>
<div>x</div>' 也会被修正
别以为只有手写 HTML 才踩坑。用 JS 设置 innerHTML 或服务端模板拼接时,只要字符串包含非法嵌套,浏览器解析器照常修正。
例如:
el.innerHTML = '<p>说明如下:</p>
- 支持 JSON
实际插入后,<ul></ul> 会被移出 <p></p>,变成兄弟节点,<p></p> 内只剩 “说明如下:”。SSR hydration 失败、React/Vue 的 DOM diff 错位,根源常在此。
安全做法是:
- 用
<div> 或 <code><section></section>替代<p></p>作为容器(它们本就是为嵌套设计的) - 若需语义化段落+区块组合,改用
<p></p>+ 后续同级<div class="block-content"> <li>动态生成前先校验结构,或用 <code>DOMParser预解析捕获异常
验证真实 DOM 结构比看源码更重要
开发中最大的盲区,是信了自己写的 HTML 源码。必须打开 DevTools → Elements 面板,看左侧展开的真实树结构 —— 那才是 JS 查询、CSS 匹配、事件绑定所依据的 DOM。
哪怕你写了 10 行嵌套代码,只要其中有一处违反 content model,整个层级就可能被重排。尤其在移动端 WebView 或旧版 Android 浏览器中,修正逻辑更激进,表现更不可控。
真正需要包裹多段混合内容(标题、列表、图片、段落)时,<p></p> 不是容器,<article></article>、<section></section> 或纯 <div> 才是正确起点。</div>










