HTML 内容模型
用 WHATWG 内容模型理解元素可包含什么,解释非法嵌套时浏览器 DOM 修复为何让 CSS/JS 行为“幽灵化”。
#type / concept
#status / growing
#tech / dev / frontend
#resource / html
[!info] 关联笔记
HTML 内容模型
这个概念为什么出现
源码写了 <p><div>...</div></p>,页面“还能显示”,但 DevTools 里 div 已经跑出 p。于是:
.desc .card选不中- 事件委托挂错节点
- 水合/SSR 警告 DOM mismatch
根因通常不是 CSS,而是违反内容模型后的解析修复。
[!abstract] 一句话理解 每个元素都有“允许的子内容类别”;HTML 解析器会尽量修复非法树,修复后的 DOM 才是真相。
最小可观察示例
场景:商品描述组件把卡片塞进段落
<!DOCTYPE html>
<html lang="zh-CN">
<body>
<p id="desc" class="desc">
SKU-42 说明
<!-- 非法:div 不是 phrasing content,不能待在 p 里 -->
<div class="card">详细参数表</div>
</p>
<script>
// 教学点:打印真实父节点,而不是相信源码缩进
const card = document.querySelector('.card')
console.log(card.parentElement && card.parentElement.id)
console.log(document.getElementById('desc').innerHTML)
</script>
</body>
</html>
建议运行:浏览器打开控制台。
期望观察(典型结果):
card 的 parent 往往不是 p#desc
#desc 的 innerHTML 在 div 前被提前关闭
结合场景关注点
- 源码树 ≠ DOM 树(修复后)。
- 选择器与 React/Vue hydrate 都以 DOM 为准。
- 组件库输出 HTML 也必须遵守模型。
核心概念与准确模型
常见内容类别(教学压缩)
| 类别 | 直觉 | 例子 |
|---|---|---|
| Metadata | head 侧元数据 | link meta title |
| Flow | 大体 body 流 | p div section ul |
| Sectioning | 参与大纲分区 | article section nav aside |
| Heading | 标题 | h1-h6 |
| Phrasing | 段落内文本级 | span a strong img |
| Embedded | 嵌入 | img video iframe |
| Interactive | 交互 | button input(上下文受限) |
规范 vs 教学:完整类别与“可感知内容”细节以 HTML spec content models 为准;上表是工程导航模型。
高频非法嵌套
p内放div/section/ul等块级 flowa内再嵌可聚焦交互(交互嵌套限制)button内再放交互控件table结构元素乱序(缺tbody时浏览器会补)
设计动机
若规范不约束子内容,每个浏览器“尽量显示”的修复策略会分叉,开发者无法共享同一 DOM 语义。内容模型是互操作合同。
边界情况
- 透明内容模型(如
a的部分情况):子内容要求随父上下文变化,不能死记硬背一个列表。 - 模板/组件抽象:JSX 里“能编译”不等于 HTML 合法。
- Markdown 渲染:错误插件可能产出非法嵌套。
常见误区
[!warning] 常见误区:页面能看见 = HTML 正确 解析修复会掩盖错误,直到选择器、a11y 树或 SSR hydrate 爆。
工程实践
- 不确定就查 MDN 元素页的 “Permitted content/parents”。
- 对关键页面做 HTML validator 或组件快照。
- 在 UI 评审里同时审 DOM 结构,不只是视觉。
本节总结
内容模型是“树能否合法存在”的规则;调试前端诡异问题时,先看 DOM 是否被静默重写。
自测题
- 为什么
p > div是经典陷阱? - 框架组件如何避免产出非法嵌套?
参考答案
p只能主要包含 phrasing;遇到 div 解析器常提前关 p,导致父链变化。- 设计 API 时限制 slot 可放内容类型;用 lint/测试检查输出 DOM;避免在 p/h* 等容器内无约束地渲染块级 children。
延伸阅读
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Content models | 规范 | 类别定义 |
| MDN: Content categories | 文档 | 可查表 |