← [ BACK_TO_NOTES ]

HTML 内容模型

用 WHATWG 内容模型理解元素可包含什么,解释非法嵌套时浏览器 DOM 修复为何让 CSS/JS 行为“幽灵化”。

#concept #growing #frontend #html

[!info] related notes

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>

建议运行:浏览器打开控制台。

期望观察(典型结果):

在这个 text/html 示例中,card 的 parent 是 body,不是 p#desc
#desc 的 innerHTML 在 div 前被提前关闭

结合场景关注点

  1. 源码树 ≠ DOM 树(修复后)。
  2. 选择器与 React/Vue hydrate 都以 DOM 为准。
  3. 组件库输出 HTML 也必须遵守模型。

核心概念与准确模型

常见内容类别(教学压缩)

类别直觉例子
Metadatahead 侧元数据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 为准;上表是工程导航模型。

高频非法嵌套

  1. p 只允许 phrasing content;div/section/ul 不属于此类,与 CSS display 是 block 还是 inline 无关。\
  2. a 内不允许交互内容、其他 a,或带 tabindex 的后代。\
  3. button 内不允许交互内容或带 tabindex 的后代。\
  4. table 内子元素放置错误;直接写 tr 本身可以合法,但 HTML 文本解析时通常会插入 tbody,改变直接子选择器的匹配。\

设计动机

若规范不约束子内容,每个浏览器“尽量显示”的修复策略会分叉,开发者无法共享同一 DOM 语义。内容模型是互操作合同。

边界情况

  • 透明内容模型(如 a 的部分情况):子内容要求随父上下文变化,不能死记硬背一个列表。
  • DOM API 与文本解析不同:appendChild 等操作可能建立不符合内容模型的树,并不会自动套用 HTML 文本解析的所有修复。SSR 文本解析与客户端建树因此可能不一致。
  • 模板/组件抽象:JSX 里“能编译”不等于 HTML 合法。
  • Markdown 渲染:错误插件可能产出非法嵌套。

常见误区

[!warning] 常见误区:页面能看见 = HTML 正确 解析修复会掩盖错误,直到选择器、a11y 树或 SSR hydrate 爆。

工程实践

  • 不确定就查 MDN 元素页的 “Permitted content/parents”。
  • 对关键页面做 HTML validator 或组件快照。
  • 在 UI 评审里同时审 DOM 结构,不只是视觉。

本节总结

内容模型是“树能否合法存在”的规则;调试前端诡异问题时,先看 DOM 是否被静默重写。

自测题

  1. 为什么 p > div 是经典陷阱?
  2. 框架组件如何避免产出非法嵌套?
参考答案
  1. p 的内容模型是 phrasing;在这里的 HTML 文本解析中,遇到 div 起始标签会提前关闭 p,导致父链变化。\
  2. 设计 API 时限制 slot 可放内容类型;用 lint/测试检查输出 DOM;避免在 p/h* 等容器内无约束地渲染块级 children。

延伸阅读

资料类型支撑内容
Content models规范类别定义
MDN: Content categories文档可查表
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本