浏览器不报错但会静默修正非法嵌套,导致实际DOM与源码不一致:<p><div>触发<p>强制闭合,生成<p></p><div>,使document.querySelector('p div')返回null、CSS选择器失配、SSR hydration失败。

为什么 p 里放 div 不报错却查不到元素
浏览器根本不会按你写的结构建 DOM——它在解析 HTML 字符串时就强制修正了。p 只允许包含 phrasing content(如 span、em、a、img),而 div 是 flow content,一出现就会触发自动闭合。
- 错误写法:
<p>文字<div class="card">区块内容</div></p> - 实际生成的 DOM 是:
<p>文字</p><div class="card">区块内容</div> -
document.querySelector('p div')永远返回null - CSS 选择器
p > div完全不匹配 - 后续 JS 若依赖
p包含该div做位置计算或事件委托,逻辑直接失效
ul 和 ol 里为什么不能直接放 p 或 div
ul 和 ol 的合法子元素只有 li。其他任何标签(包括 p、div、h3)或空白文本若未包裹在 li 中,都会被浏览器视为非法内容,触发自动拆分逻辑。
- 错误写法:
<ol><p>Item one</p> Item two</ol> - 实际解析为:
<ol></ol><p>Item one</p><ol><li>Item two</li></ol> - 序号重置、语义丢失、
list-style样式失效 -
document.querySelectorAll('ol li')可能漏掉第一个“item”,因为它已不在ol内 - 想让段落作为列表项?用
<li><p>...</p></li>,而不是反过来
table 看似能省略 tbody,但为什么显式写出更稳妥
浏览器确实会自动补 tbody,但这不是“可选”的宽容,而是强制合规的兜底行为。真实 DOM 路径是 table > tbody > tr,而非你写的 table > tr。
- 错误假设:
document.querySelector('table tr:first-child')能命中第一行 → 实际匹配的是tbody下的第一个tr -
querySelectorAll('tr')返回的节点顺序可能跨多个tbody,与视觉顺序不一致 - 服务端渲染(SSR)做 hydration 校验时,HTML 字符串不含
tbody,但客户端 DOM 含有,导致校验失败 - 旧版 IE 对自动补全行为不一致,表格可能整行消失或错位
- 正确写法:始终显式写出
<tbody>,哪怕只有一组数据
自闭合标签加 /> 或多余 </img> 会怎样
img、input、br、hr 是 void 元素,在 HTML5 中禁止闭合。写成 <img src="x" /> 合法,但写成 <img src="x"></img> 就变成两个标签:前者被忽略,后者被当作未知容器处理。
立即学习“前端免费学习笔记(深入)”;
- 错误写法:
<div><img src="a.jpg"></img><p>文字</p></div> - 实际 DOM 可能是:
<div><img src="a.jpg"></div><img><p>文字</p> - 后续
div突然变成img的子元素(DevTools 缩进异常) -
document.body.children数量变多且类型混乱 - Vue/React hydration 失败,报 “Hydration failed”
- 统一用
<img src="x">(HTML5 推荐省略/>),不要加</img>



















